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,10 +1,8 @@
1
1
  // @ts-check
2
-
3
- import {resolveFrontendModelClass} from "./model-registry.js"
4
- import {normalizeRansackGroup, parseRansackSort} from "../utils/ransack.js"
5
- import {isModelScopeDescriptor} from "../utils/model-scope.js"
6
- import isPlainObject from "../utils/plain-object.js"
7
-
2
+ import { resolveFrontendModelClass } from "./model-registry.js";
3
+ import { normalizeRansackGroup, parseRansackSort } from "../utils/ransack.js";
4
+ import { isModelScopeDescriptor } from "../utils/model-scope.js";
5
+ import isPlainObject from "../utils/plain-object.js";
8
6
  /**
9
7
  * FrontendModelSearch type.
10
8
  * @typedef {object} FrontendModelSearch
@@ -71,70 +69,57 @@ import isPlainObject from "../utils/plain-object.js"
71
69
  * @property {FrontendModelEventFilterPayload | null} eventFilterPayload - Normalized event filter payload, or null when unfiltered.
72
70
  * @property {FrontendModelProjectionPayload} projectionPayload - Normalized event serialization projection payload.
73
71
  */
74
-
75
72
  /**
76
73
  * Runs the normalizePreload helper.
77
74
  * @param {import("../database/query/index.js").NestedPreloadRecord | string | Array<string | import("../database/query/index.js").NestedPreloadRecord> | boolean | undefined | null} preload - Preload shorthand.
78
75
  * @returns {import("../database/query/index.js").NestedPreloadRecord} - Normalized preload.
79
76
  */
80
77
  export function normalizePreload(preload) {
81
- if (!preload) return {}
82
-
83
- if (preload === true) return {}
84
-
85
- if (typeof preload === "string") {
86
- return {[preload]: true}
87
- }
88
-
89
- if (Array.isArray(preload)) {
78
+ if (!preload)
79
+ return {};
80
+ if (preload === true)
81
+ return {};
82
+ if (typeof preload === "string") {
83
+ return { [preload]: true };
84
+ }
85
+ if (Array.isArray(preload)) {
86
+ /**
87
+ * Normalized.
88
+ @type {import("../database/query/index.js").NestedPreloadRecord} */
89
+ const normalized = {};
90
+ for (const entry of preload) {
91
+ if (typeof entry === "string") {
92
+ normalized[entry] = true;
93
+ continue;
94
+ }
95
+ if (isPlainObject(entry)) {
96
+ mergePreloadRecord(normalized, normalizePreload(entry));
97
+ continue;
98
+ }
99
+ throw new Error(`Invalid preload entry type: ${typeof entry}`);
100
+ }
101
+ return normalized;
102
+ }
103
+ if (!isPlainObject(preload)) {
104
+ throw new Error(`Invalid preload type: ${typeof preload}`);
105
+ }
90
106
  /**
91
107
  * Normalized.
92
108
  @type {import("../database/query/index.js").NestedPreloadRecord} */
93
- const normalized = {}
94
-
95
- for (const entry of preload) {
96
- if (typeof entry === "string") {
97
- normalized[entry] = true
98
- continue
99
- }
100
-
101
- if (isPlainObject(entry)) {
102
- mergePreloadRecord(normalized, normalizePreload(entry))
103
- continue
104
- }
105
-
106
- throw new Error(`Invalid preload entry type: ${typeof entry}`)
107
- }
108
-
109
- return normalized
110
- }
111
-
112
- if (!isPlainObject(preload)) {
113
- throw new Error(`Invalid preload type: ${typeof preload}`)
114
- }
115
-
116
- /**
117
- * Normalized.
118
- @type {import("../database/query/index.js").NestedPreloadRecord} */
119
- const normalized = {}
120
-
121
- for (const [relationshipName, relationshipPreload] of Object.entries(preload)) {
122
- if (relationshipPreload === true || relationshipPreload === false) {
123
- normalized[relationshipName] = relationshipPreload
124
- continue
125
- }
126
-
127
- if (typeof relationshipPreload === "string" || Array.isArray(relationshipPreload) || isPlainObject(relationshipPreload)) {
128
- normalized[relationshipName] = normalizePreload(relationshipPreload)
129
- continue
130
- }
131
-
132
- throw new Error(`Invalid preload value for ${relationshipName}: ${typeof relationshipPreload}`)
133
- }
134
-
135
- return normalized
109
+ const normalized = {};
110
+ for (const [relationshipName, relationshipPreload] of Object.entries(preload)) {
111
+ if (relationshipPreload === true || relationshipPreload === false) {
112
+ normalized[relationshipName] = relationshipPreload;
113
+ continue;
114
+ }
115
+ if (typeof relationshipPreload === "string" || Array.isArray(relationshipPreload) || isPlainObject(relationshipPreload)) {
116
+ normalized[relationshipName] = normalizePreload(relationshipPreload);
117
+ continue;
118
+ }
119
+ throw new Error(`Invalid preload value for ${relationshipName}: ${typeof relationshipPreload}`);
120
+ }
121
+ return normalized;
136
122
  }
137
-
138
123
  /**
139
124
  * Normalize the shorthand `withCount` argument from the frontend-model
140
125
  * query API into the strict internal entries used in the transport
@@ -144,54 +129,45 @@ export function normalizePreload(preload) {
144
129
  * @returns {Array<{attributeName: string, relationshipName: string, where?: Record<string, ?>}>}
145
130
  */
146
131
  function normalizeWithCountFrontend(spec) {
147
- if (spec == null) return []
148
-
149
- if (typeof spec === "string") {
150
- return [{attributeName: `${spec}Count`, relationshipName: spec}]
151
- }
152
-
153
- if (Array.isArray(spec)) {
154
- return spec.flatMap((item) => {
155
- if (typeof item !== "string") {
156
- throw new Error(`withCount array entries must be strings; got ${typeof item}`)
157
- }
158
-
159
- return [{attributeName: `${item}Count`, relationshipName: item}]
160
- })
161
- }
162
-
163
- if (!isPlainObject(spec)) {
164
- throw new Error(`Invalid withCount spec: ${typeof spec}`)
165
- }
166
-
167
- const entries = []
168
-
169
- for (const [key, value] of Object.entries(spec)) {
170
- if (value === true) {
171
- entries.push({attributeName: `${key}Count`, relationshipName: key})
172
- continue
173
- }
174
-
175
- if (value === false) continue
176
-
177
- if (isPlainObject(value)) {
178
- const options = /**
179
- * Narrows the runtime value to the documented type.
180
- @type {{relationship?: string, where?: Record<string, ?>}} */ (value)
181
- entries.push({
182
- attributeName: key,
183
- relationshipName: options.relationship || key,
184
- where: options.where
185
- })
186
- continue
187
- }
188
-
189
- throw new Error(`Invalid withCount value for ${key}: ${typeof value}`)
190
- }
191
-
192
- return entries
132
+ if (spec == null)
133
+ return [];
134
+ if (typeof spec === "string") {
135
+ return [{ attributeName: `${spec}Count`, relationshipName: spec }];
136
+ }
137
+ if (Array.isArray(spec)) {
138
+ return spec.flatMap((item) => {
139
+ if (typeof item !== "string") {
140
+ throw new Error(`withCount array entries must be strings; got ${typeof item}`);
141
+ }
142
+ return [{ attributeName: `${item}Count`, relationshipName: item }];
143
+ });
144
+ }
145
+ if (!isPlainObject(spec)) {
146
+ throw new Error(`Invalid withCount spec: ${typeof spec}`);
147
+ }
148
+ const entries = [];
149
+ for (const [key, value] of Object.entries(spec)) {
150
+ if (value === true) {
151
+ entries.push({ attributeName: `${key}Count`, relationshipName: key });
152
+ continue;
153
+ }
154
+ if (value === false)
155
+ continue;
156
+ if (isPlainObject(value)) {
157
+ const options = /**
158
+ * Narrows the runtime value to the documented type.
159
+ @type {{relationship?: string, where?: Record<string, ?>}} */ (value);
160
+ entries.push({
161
+ attributeName: key,
162
+ relationshipName: options.relationship || key,
163
+ where: options.where
164
+ });
165
+ continue;
166
+ }
167
+ throw new Error(`Invalid withCount value for ${key}: ${typeof value}`);
168
+ }
169
+ return entries;
193
170
  }
194
-
195
171
  /**
196
172
  * Normalize a frontend `.abilities(...)` spec into a flat list of
197
173
  * `{modelName, actions}` entries. Accepts the flat actions-array
@@ -203,53 +179,43 @@ function normalizeWithCountFrontend(spec) {
203
179
  * @returns {Array<{modelName: string, actions: string[]}>}
204
180
  */
205
181
  function normalizeAbilitiesSpec(spec, rootModelClass) {
206
- if (spec == null) return []
207
-
208
- if (Array.isArray(spec)) {
209
- for (const action of spec) {
210
- if (typeof action !== "string" || action.length < 1) {
211
- throw new Error(`abilities flat-form actions must be non-empty strings; got ${typeof action}`)
212
- }
213
- }
214
-
215
- const rootModelName = typeof rootModelClass?.getModelName === "function"
216
- ? rootModelClass.getModelName()
217
- : undefined
218
- if (!rootModelName) {
219
- throw new Error("abilities flat-form requires a root model class with getModelName()")
220
- }
221
-
222
- return [{actions: [...spec], modelName: rootModelName}]
223
- }
224
-
225
- if (!isPlainObject(spec)) {
226
- throw new Error(`Invalid abilities spec: ${typeof spec}`)
227
- }
228
-
229
- /**
230
- * Entries.
231
- @type {Array<{modelName: string, actions: string[]}>} */
232
- const entries = []
233
-
234
- for (const [modelName, actions] of Object.entries(spec)) {
235
- if (!Array.isArray(actions)) {
236
- throw new Error(`abilities[${modelName}] must be an array of action names; got ${typeof actions}`)
237
- }
238
-
239
- const sanitized = actions.map((action) => {
240
- if (typeof action !== "string" || action.length < 1) {
241
- throw new Error(`abilities[${modelName}] entries must be non-empty strings; got ${typeof action}`)
242
- }
243
-
244
- return action
245
- })
246
-
247
- entries.push({actions: sanitized, modelName})
248
- }
249
-
250
- return entries
182
+ if (spec == null)
183
+ return [];
184
+ if (Array.isArray(spec)) {
185
+ for (const action of spec) {
186
+ if (typeof action !== "string" || action.length < 1) {
187
+ throw new Error(`abilities flat-form actions must be non-empty strings; got ${typeof action}`);
188
+ }
189
+ }
190
+ const rootModelName = typeof rootModelClass?.getModelName === "function"
191
+ ? rootModelClass.getModelName()
192
+ : undefined;
193
+ if (!rootModelName) {
194
+ throw new Error("abilities flat-form requires a root model class with getModelName()");
195
+ }
196
+ return [{ actions: [...spec], modelName: rootModelName }];
197
+ }
198
+ if (!isPlainObject(spec)) {
199
+ throw new Error(`Invalid abilities spec: ${typeof spec}`);
200
+ }
201
+ /**
202
+ * Entries.
203
+ @type {Array<{modelName: string, actions: string[]}>} */
204
+ const entries = [];
205
+ for (const [modelName, actions] of Object.entries(spec)) {
206
+ if (!Array.isArray(actions)) {
207
+ throw new Error(`abilities[${modelName}] must be an array of action names; got ${typeof actions}`);
208
+ }
209
+ const sanitized = actions.map((action) => {
210
+ if (typeof action !== "string" || action.length < 1) {
211
+ throw new Error(`abilities[${modelName}] entries must be non-empty strings; got ${typeof action}`);
212
+ }
213
+ return action;
214
+ });
215
+ entries.push({ actions: sanitized, modelName });
216
+ }
217
+ return entries;
251
218
  }
252
-
253
219
  /**
254
220
  * Runs merge preload record.
255
221
  * @param {import("../database/query/index.js").NestedPreloadRecord} targetPreload - Existing preload data.
@@ -257,41 +223,34 @@ function normalizeAbilitiesSpec(spec, rootModelClass) {
257
223
  * @returns {void}
258
224
  */
259
225
  function mergePreloadRecord(targetPreload, incomingPreload) {
260
- for (const [relationshipName, incomingValue] of Object.entries(incomingPreload)) {
261
- const existingValue = targetPreload[relationshipName]
262
-
263
- if (incomingValue === false) {
264
- targetPreload[relationshipName] = false
265
- continue
266
- }
267
-
268
- if (incomingValue === true) {
269
- if (existingValue === undefined) {
270
- targetPreload[relationshipName] = true
271
- }
272
- continue
273
- }
274
-
275
- if (!isPlainObject(incomingValue)) {
276
- throw new Error(`Invalid preload value for ${relationshipName}: ${typeof incomingValue}`)
277
- }
278
-
279
- if (isPlainObject(existingValue)) {
280
- mergePreloadRecord(
281
- /**
282
- * Narrows the runtime value to the documented type.
283
- @type {import("../database/query/index.js").NestedPreloadRecord} */ (existingValue),
284
- /**
285
- * Narrows the runtime value to the documented type.
286
- @type {import("../database/query/index.js").NestedPreloadRecord} */ (incomingValue)
287
- )
288
- continue
226
+ for (const [relationshipName, incomingValue] of Object.entries(incomingPreload)) {
227
+ const existingValue = targetPreload[relationshipName];
228
+ if (incomingValue === false) {
229
+ targetPreload[relationshipName] = false;
230
+ continue;
231
+ }
232
+ if (incomingValue === true) {
233
+ if (existingValue === undefined) {
234
+ targetPreload[relationshipName] = true;
235
+ }
236
+ continue;
237
+ }
238
+ if (!isPlainObject(incomingValue)) {
239
+ throw new Error(`Invalid preload value for ${relationshipName}: ${typeof incomingValue}`);
240
+ }
241
+ if (isPlainObject(existingValue)) {
242
+ mergePreloadRecord(
243
+ /**
244
+ * Narrows the runtime value to the documented type.
245
+ @type {import("../database/query/index.js").NestedPreloadRecord} */ (existingValue),
246
+ /**
247
+ * Narrows the runtime value to the documented type.
248
+ @type {import("../database/query/index.js").NestedPreloadRecord} */ (incomingValue));
249
+ continue;
250
+ }
251
+ targetPreload[relationshipName] = normalizePreload(incomingValue);
289
252
  }
290
-
291
- targetPreload[relationshipName] = normalizePreload(incomingValue)
292
- }
293
253
  }
294
-
295
254
  /**
296
255
  * Runs normalize select.
297
256
  * @param {?} select - Select payload.
@@ -299,57 +258,47 @@ function mergePreloadRecord(targetPreload, incomingPreload) {
299
258
  * @returns {Record<string, string[]>} - Normalized model-name keyed select record.
300
259
  */
301
260
  function normalizeSelect(select, rootModelName = null) {
302
- if (!select) return {}
303
-
304
- if (typeof select === "string") {
305
- if (!rootModelName) throw new Error("Invalid select shorthand without root model name")
306
-
307
- return {[rootModelName]: [select]}
308
- }
309
-
310
- if (Array.isArray(select)) {
311
- if (!rootModelName) throw new Error("Invalid select shorthand without root model name")
312
-
313
- for (const attributeName of select) {
314
- if (typeof attributeName !== "string") {
315
- throw new Error(`Invalid select attribute for ${rootModelName}: ${typeof attributeName}`)
316
- }
317
- }
318
-
319
- return {[rootModelName]: Array.from(new Set(select))}
320
- }
321
-
322
- if (!isPlainObject(select)) {
323
- throw new Error(`Invalid select type: ${typeof select}`)
324
- }
325
-
326
- /**
327
- * Normalized.
328
- @type {Record<string, string[]>} */
329
- const normalized = {}
330
-
331
- for (const [modelName, selection] of Object.entries(select)) {
332
- if (typeof selection === "string") {
333
- normalized[modelName] = [selection]
334
- continue
335
- }
336
-
337
- if (!Array.isArray(selection)) {
338
- throw new Error(`Invalid select value for ${modelName}: ${typeof selection}`)
339
- }
340
-
341
- for (const attributeName of selection) {
342
- if (typeof attributeName !== "string") {
343
- throw new Error(`Invalid select attribute for ${modelName}: ${typeof attributeName}`)
344
- }
345
- }
346
-
347
- normalized[modelName] = Array.from(new Set(selection))
348
- }
349
-
350
- return normalized
261
+ if (!select)
262
+ return {};
263
+ if (typeof select === "string") {
264
+ if (!rootModelName)
265
+ throw new Error("Invalid select shorthand without root model name");
266
+ return { [rootModelName]: [select] };
267
+ }
268
+ if (Array.isArray(select)) {
269
+ if (!rootModelName)
270
+ throw new Error("Invalid select shorthand without root model name");
271
+ for (const attributeName of select) {
272
+ if (typeof attributeName !== "string") {
273
+ throw new Error(`Invalid select attribute for ${rootModelName}: ${typeof attributeName}`);
274
+ }
275
+ }
276
+ return { [rootModelName]: Array.from(new Set(select)) };
277
+ }
278
+ if (!isPlainObject(select)) {
279
+ throw new Error(`Invalid select type: ${typeof select}`);
280
+ }
281
+ /**
282
+ * Normalized.
283
+ @type {Record<string, string[]>} */
284
+ const normalized = {};
285
+ for (const [modelName, selection] of Object.entries(select)) {
286
+ if (typeof selection === "string") {
287
+ normalized[modelName] = [selection];
288
+ continue;
289
+ }
290
+ if (!Array.isArray(selection)) {
291
+ throw new Error(`Invalid select value for ${modelName}: ${typeof selection}`);
292
+ }
293
+ for (const attributeName of selection) {
294
+ if (typeof attributeName !== "string") {
295
+ throw new Error(`Invalid select attribute for ${modelName}: ${typeof attributeName}`);
296
+ }
297
+ }
298
+ normalized[modelName] = Array.from(new Set(selection));
299
+ }
300
+ return normalized;
351
301
  }
352
-
353
302
  /**
354
303
  * Runs merge select record.
355
304
  * @param {Record<string, string[]>} targetSelect - Existing select record.
@@ -357,37 +306,32 @@ function normalizeSelect(select, rootModelName = null) {
357
306
  * @returns {void}
358
307
  */
359
308
  function mergeSelectRecord(targetSelect, incomingSelect) {
360
- for (const [modelName, incomingAttributes] of Object.entries(incomingSelect)) {
361
- const existingAttributes = targetSelect[modelName] || []
362
-
363
- targetSelect[modelName] = Array.from(new Set([...existingAttributes, ...incomingAttributes]))
364
- }
309
+ for (const [modelName, incomingAttributes] of Object.entries(incomingSelect)) {
310
+ const existingAttributes = targetSelect[modelName] || [];
311
+ targetSelect[modelName] = Array.from(new Set([...existingAttributes, ...incomingAttributes]));
312
+ }
365
313
  }
366
-
367
314
  /**
368
315
  * Runs the normalizeSearchOperator helper.
369
316
  * @param {string} operator - Raw search operator.
370
317
  * @returns {"eq" | "like" | "notEq" | "gt" | "gteq" | "lt" | "lteq"} - Normalized operator.
371
318
  */
372
319
  export function normalizeSearchOperator(operator) {
373
- const operatorAliases = {
374
- "<": "lt",
375
- "<=": "lteq",
376
- ">": "gt",
377
- ">=": "gteq"
378
- }
379
- const normalizedOperator = operatorAliases[/**
380
- * Narrows the runtime value to the documented type.
381
- @type {"<" | "<=" | ">" | ">="} */ (operator)] || operator
382
- const supportedOperators = new Set(["eq", "like", "notEq", "gt", "gteq", "lt", "lteq"])
383
-
384
- if (!supportedOperators.has(normalizedOperator)) {
385
- throw new Error(`search operator must be one of: eq, like, notEq, gt, gteq, lt, lteq, >, >=, <, <= (got: ${operator})`)
386
- }
387
-
388
- return /** Narrows the runtime value to the documented type. @type {"eq" | "like" | "notEq" | "gt" | "gteq" | "lt" | "lteq"} */ (normalizedOperator)
320
+ const operatorAliases = {
321
+ "<": "lt",
322
+ "<=": "lteq",
323
+ ">": "gt",
324
+ ">=": "gteq"
325
+ };
326
+ const normalizedOperator = operatorAliases[ /**
327
+ * Narrows the runtime value to the documented type.
328
+ @type {"<" | "<=" | ">" | ">="} */(operator)] || operator;
329
+ const supportedOperators = new Set(["eq", "like", "notEq", "gt", "gteq", "lt", "lteq"]);
330
+ if (!supportedOperators.has(normalizedOperator)) {
331
+ throw new Error(`search operator must be one of: eq, like, notEq, gt, gteq, lt, lteq, >, >=, <, <= (got: ${operator})`);
332
+ }
333
+ return /** Narrows the runtime value to the documented type. @type {"eq" | "like" | "notEq" | "gt" | "gteq" | "lt" | "lteq"} */ (normalizedOperator);
389
334
  }
390
-
391
335
  /**
392
336
  * Runs merge join record.
393
337
  * @param {Record<string, ?>} targetJoins - Existing join record.
@@ -395,85 +339,69 @@ export function normalizeSearchOperator(operator) {
395
339
  * @returns {void}
396
340
  */
397
341
  function mergeJoinRecord(targetJoins, incomingJoins) {
398
- for (const [relationshipName, incomingValue] of Object.entries(incomingJoins)) {
399
- const existingValue = targetJoins[relationshipName]
400
-
401
- if (incomingValue === true) {
402
- if (existingValue === undefined) {
403
- targetJoins[relationshipName] = true
404
- }
405
- continue
406
- }
407
-
408
- if (!isPlainObject(incomingValue)) {
409
- throw new Error(`Invalid join value for ${relationshipName}: ${typeof incomingValue}`)
410
- }
411
-
412
- if (isPlainObject(existingValue)) {
413
- mergeJoinRecord(existingValue, incomingValue)
414
- continue
415
- }
416
-
417
- if (existingValue === true) {
418
- targetJoins[relationshipName] = normalizeJoins(incomingValue)
419
- continue
420
- }
421
-
422
- targetJoins[relationshipName] = normalizeJoins(incomingValue)
423
- }
342
+ for (const [relationshipName, incomingValue] of Object.entries(incomingJoins)) {
343
+ const existingValue = targetJoins[relationshipName];
344
+ if (incomingValue === true) {
345
+ if (existingValue === undefined) {
346
+ targetJoins[relationshipName] = true;
347
+ }
348
+ continue;
349
+ }
350
+ if (!isPlainObject(incomingValue)) {
351
+ throw new Error(`Invalid join value for ${relationshipName}: ${typeof incomingValue}`);
352
+ }
353
+ if (isPlainObject(existingValue)) {
354
+ mergeJoinRecord(existingValue, incomingValue);
355
+ continue;
356
+ }
357
+ if (existingValue === true) {
358
+ targetJoins[relationshipName] = normalizeJoins(incomingValue);
359
+ continue;
360
+ }
361
+ targetJoins[relationshipName] = normalizeJoins(incomingValue);
362
+ }
424
363
  }
425
-
426
364
  /**
427
365
  * Runs the normalizeJoins helper.
428
366
  * @param {?} joins - Join payload.
429
367
  * @returns {Record<string, ?>} - Normalized relationship descriptor joins.
430
368
  */
431
369
  export function normalizeJoins(joins) {
432
- if (!joins) return {}
433
-
434
- if (Array.isArray(joins)) {
370
+ if (!joins)
371
+ return {};
372
+ if (Array.isArray(joins)) {
373
+ /**
374
+ * Normalized.
375
+ @type {Record<string, ?>} */
376
+ const normalized = {};
377
+ for (const joinEntry of joins) {
378
+ if (!isPlainObject(joinEntry)) {
379
+ throw new Error(`Invalid joins entry type: ${typeof joinEntry}`);
380
+ }
381
+ mergeJoinRecord(normalized, normalizeJoins(joinEntry));
382
+ }
383
+ return normalized;
384
+ }
385
+ if (!isPlainObject(joins)) {
386
+ throw new Error(`Invalid joins type: ${typeof joins}`);
387
+ }
435
388
  /**
436
389
  * Normalized.
437
390
  @type {Record<string, ?>} */
438
- const normalized = {}
439
-
440
- for (const joinEntry of joins) {
441
- if (!isPlainObject(joinEntry)) {
442
- throw new Error(`Invalid joins entry type: ${typeof joinEntry}`)
443
- }
444
-
445
- mergeJoinRecord(normalized, normalizeJoins(joinEntry))
446
- }
447
-
448
- return normalized
449
- }
450
-
451
- if (!isPlainObject(joins)) {
452
- throw new Error(`Invalid joins type: ${typeof joins}`)
453
- }
454
-
455
- /**
456
- * Normalized.
457
- @type {Record<string, ?>} */
458
- const normalized = {}
459
-
460
- for (const [relationshipName, relationshipJoin] of Object.entries(joins)) {
461
- if (relationshipJoin === true) {
462
- normalized[relationshipName] = true
463
- continue
464
- }
465
-
466
- if (isPlainObject(relationshipJoin)) {
467
- normalized[relationshipName] = normalizeJoins(relationshipJoin)
468
- continue
469
- }
470
-
471
- throw new Error(`Invalid join definition for "${relationshipName}": ${typeof relationshipJoin}`)
472
- }
473
-
474
- return normalized
391
+ const normalized = {};
392
+ for (const [relationshipName, relationshipJoin] of Object.entries(joins)) {
393
+ if (relationshipJoin === true) {
394
+ normalized[relationshipName] = true;
395
+ continue;
396
+ }
397
+ if (isPlainObject(relationshipJoin)) {
398
+ normalized[relationshipName] = normalizeJoins(relationshipJoin);
399
+ continue;
400
+ }
401
+ throw new Error(`Invalid join definition for "${relationshipName}": ${typeof relationshipJoin}`);
402
+ }
403
+ return normalized;
475
404
  }
476
-
477
405
  /**
478
406
  * FrontendModelSort type.
479
407
  * @typedef {object} FrontendModelSort
@@ -481,72 +409,70 @@ export function normalizeJoins(joins) {
481
409
  * @property {"asc" | "desc"} direction - Sort direction.
482
410
  * @property {string[]} path - Relationship path from root model.
483
411
  */
484
-
485
412
  /**
486
413
  * FrontendModelGroup type.
487
414
  * @typedef {object} FrontendModelGroup
488
415
  * @property {string} column - Attribute name to group by.
489
416
  * @property {string[]} path - Relationship path from root model.
490
417
  */
491
-
492
418
  /**
493
419
  * FrontendModelPluck type.
494
420
  * @typedef {object} FrontendModelPluck
495
421
  * @property {string} column - Attribute name to pluck.
496
422
  * @property {string[]} path - Relationship path from root model.
497
423
  */
498
-
499
424
  /**
500
425
  * Runs normalize sort direction.
501
426
  * @param {?} direction - Direction value.
502
427
  * @returns {"asc" | "desc"} - Normalized direction.
503
428
  */
504
429
  function normalizeSortDirection(direction) {
505
- if (typeof direction !== "string") {
506
- throw new Error(`Invalid sort direction type: ${typeof direction}`)
507
- }
508
-
509
- const normalizedDirection = direction.trim().toLowerCase()
510
-
511
- if (normalizedDirection !== "asc" && normalizedDirection !== "desc") {
512
- throw new Error(`Invalid sort direction: ${direction}`)
513
- }
514
-
515
- return normalizedDirection
430
+ if (typeof direction !== "string") {
431
+ throw new Error(`Invalid sort direction type: ${typeof direction}`);
432
+ }
433
+ const normalizedDirection = direction.trim().toLowerCase();
434
+ if (normalizedDirection !== "asc" && normalizedDirection !== "desc") {
435
+ throw new Error(`Invalid sort direction: ${direction}`);
436
+ }
437
+ return normalizedDirection;
516
438
  }
517
-
518
439
  /**
519
440
  * Check whether a value is a two-item `[column, direction]` sort tuple.
520
441
  * @param {?} value - Candidate tuple.
521
442
  * @returns {value is [string, string]} - Whether value is a sort tuple.
522
443
  */
523
444
  function sortTuple(value) {
524
- if (!Array.isArray(value)) return false
525
- if (value.length !== 2) return false
526
- if (typeof value[0] !== "string") return false
527
- if (typeof value[1] !== "string") return false
528
- if (value[0].trim().length < 1) return false
529
-
530
- const direction = value[1].trim().toLowerCase()
531
-
532
- return direction === "asc" || direction === "desc"
445
+ if (!Array.isArray(value))
446
+ return false;
447
+ if (value.length !== 2)
448
+ return false;
449
+ if (typeof value[0] !== "string")
450
+ return false;
451
+ if (typeof value[1] !== "string")
452
+ return false;
453
+ if (value[0].trim().length < 1)
454
+ return false;
455
+ const direction = value[1].trim().toLowerCase();
456
+ return direction === "asc" || direction === "desc";
533
457
  }
534
-
535
458
  /**
536
459
  * Check whether a value is a structured sort descriptor with a relationship path.
537
460
  * @param {?} value - Candidate descriptor.
538
461
  * @returns {value is {column: string, direction: string, path: string[]}} - Whether value is an explicit sort descriptor object.
539
462
  */
540
463
  function sortDescriptor(value) {
541
- if (!isPlainObject(value)) return false
542
- if (!("column" in value) || !("direction" in value) || !("path" in value)) return false
543
- if (typeof value.column !== "string") return false
544
- if (typeof value.direction !== "string") return false
545
- if (!Array.isArray(value.path)) return false
546
-
547
- return value.path.every((pathEntry) => typeof pathEntry === "string")
464
+ if (!isPlainObject(value))
465
+ return false;
466
+ if (!("column" in value) || !("direction" in value) || !("path" in value))
467
+ return false;
468
+ if (typeof value.column !== "string")
469
+ return false;
470
+ if (typeof value.direction !== "string")
471
+ return false;
472
+ if (!Array.isArray(value.path))
473
+ return false;
474
+ return value.path.every((pathEntry) => typeof pathEntry === "string");
548
475
  }
549
-
550
476
  /**
551
477
  * Parse a string shorthand into a sort descriptor.
552
478
  * @param {string} sortValue - Sort string.
@@ -554,49 +480,38 @@ function sortDescriptor(value) {
554
480
  * @returns {FrontendModelSort} - Normalized sort descriptor.
555
481
  */
556
482
  function parseSortString(sortValue, path = []) {
557
- const trimmed = sortValue.trim()
558
-
559
- if (trimmed.length < 1) {
560
- throw new Error("sort value must be a non-empty string")
561
- }
562
-
563
- if (trimmed.startsWith("-")) {
564
- const column = trimmed.slice(1).trim()
565
-
483
+ const trimmed = sortValue.trim();
484
+ if (trimmed.length < 1) {
485
+ throw new Error("sort value must be a non-empty string");
486
+ }
487
+ if (trimmed.startsWith("-")) {
488
+ const column = trimmed.slice(1).trim();
489
+ if (column.length < 1) {
490
+ throw new Error(`Invalid sort definition: ${sortValue}`);
491
+ }
492
+ return {
493
+ column,
494
+ direction: "desc",
495
+ path: [...path]
496
+ };
497
+ }
498
+ const sortParts = trimmed.split(/\s+/).filter(Boolean);
499
+ if (sortParts.length > 2) {
500
+ throw new Error(`Invalid sort definition: ${sortValue}`);
501
+ }
502
+ const column = sortParts[0];
566
503
  if (column.length < 1) {
567
- throw new Error(`Invalid sort definition: ${sortValue}`)
504
+ throw new Error(`Invalid sort definition: ${sortValue}`);
568
505
  }
569
-
506
+ const direction = sortParts.length === 2
507
+ ? normalizeSortDirection(sortParts[1])
508
+ : "asc";
570
509
  return {
571
- column,
572
- direction: "desc",
573
- path: [...path]
574
- }
575
- }
576
-
577
- const sortParts = trimmed.split(/\s+/).filter(Boolean)
578
-
579
- if (sortParts.length > 2) {
580
- throw new Error(`Invalid sort definition: ${sortValue}`)
581
- }
582
-
583
- const column = sortParts[0]
584
-
585
- if (column.length < 1) {
586
- throw new Error(`Invalid sort definition: ${sortValue}`)
587
- }
588
-
589
- const direction = sortParts.length === 2
590
- ? normalizeSortDirection(sortParts[1])
591
- : "asc"
592
-
593
- return {
594
- column,
595
- direction,
596
- path: [...path]
597
- }
510
+ column,
511
+ direction,
512
+ path: [...path]
513
+ };
598
514
  }
599
-
600
515
  /**
601
516
  * Parse a tuple shorthand into a sort descriptor.
602
517
  * @param {[string, string]} sortValue - Sort tuple.
@@ -604,20 +519,17 @@ function parseSortString(sortValue, path = []) {
604
519
  * @returns {FrontendModelSort} - Normalized sort descriptor.
605
520
  */
606
521
  function parseSortTuple(sortValue, path = []) {
607
- const [columnValue, directionValue] = sortValue
608
- const column = columnValue.trim()
609
-
610
- if (column.length < 1) {
611
- throw new Error("sort tuple column must be a non-empty string")
612
- }
613
-
614
- return {
615
- column,
616
- direction: normalizeSortDirection(directionValue),
617
- path: [...path]
618
- }
522
+ const [columnValue, directionValue] = sortValue;
523
+ const column = columnValue.trim();
524
+ if (column.length < 1) {
525
+ throw new Error("sort tuple column must be a non-empty string");
526
+ }
527
+ return {
528
+ column,
529
+ direction: normalizeSortDirection(directionValue),
530
+ path: [...path]
531
+ };
619
532
  }
620
-
621
533
  /**
622
534
  * Normalize a nested object sort payload into flat sort descriptors.
623
535
  * @param {Record<string, ?>} sortValue - Nested sort object.
@@ -625,120 +537,99 @@ function parseSortTuple(sortValue, path = []) {
625
537
  * @returns {FrontendModelSort[]} - Normalized sort descriptors.
626
538
  */
627
539
  function normalizeSortObject(sortValue, path) {
628
- /**
629
- * Normalized sorts.
630
- @type {FrontendModelSort[]} */
631
- const normalizedSorts = []
632
-
633
- for (const [sortKey, sortEntry] of Object.entries(sortValue)) {
634
- if (typeof sortEntry === "string") {
635
- normalizedSorts.push({
636
- column: sortKey,
637
- direction: normalizeSortDirection(sortEntry),
638
- path: [...path]
639
- })
640
- continue
641
- }
642
-
643
- if (sortTuple(sortEntry)) {
644
- normalizedSorts.push(parseSortTuple(sortEntry, [...path, sortKey]))
645
- continue
646
- }
647
-
648
- if (Array.isArray(sortEntry)) {
649
- if (sortEntry.length < 1) {
650
- throw new Error(`Invalid sort definition for "${sortKey}": empty array`)
651
- }
652
-
653
- for (const nestedSortEntry of sortEntry) {
654
- if (!sortTuple(nestedSortEntry)) {
655
- throw new Error(`Invalid sort definition for "${sortKey}": expected [column, direction] tuples`)
656
- }
657
-
658
- normalizedSorts.push(parseSortTuple(nestedSortEntry, [...path, sortKey]))
659
- }
660
- continue
661
- }
662
-
663
- if (isPlainObject(sortEntry)) {
664
- normalizedSorts.push(...normalizeSortObject(sortEntry, [...path, sortKey]))
665
- continue
666
- }
667
-
668
- throw new Error(`Invalid sort definition for "${sortKey}": ${typeof sortEntry}`)
669
- }
670
-
671
- return normalizedSorts
540
+ /**
541
+ * Normalized sorts.
542
+ @type {FrontendModelSort[]} */
543
+ const normalizedSorts = [];
544
+ for (const [sortKey, sortEntry] of Object.entries(sortValue)) {
545
+ if (typeof sortEntry === "string") {
546
+ normalizedSorts.push({
547
+ column: sortKey,
548
+ direction: normalizeSortDirection(sortEntry),
549
+ path: [...path]
550
+ });
551
+ continue;
552
+ }
553
+ if (sortTuple(sortEntry)) {
554
+ normalizedSorts.push(parseSortTuple(sortEntry, [...path, sortKey]));
555
+ continue;
556
+ }
557
+ if (Array.isArray(sortEntry)) {
558
+ if (sortEntry.length < 1) {
559
+ throw new Error(`Invalid sort definition for "${sortKey}": empty array`);
560
+ }
561
+ for (const nestedSortEntry of sortEntry) {
562
+ if (!sortTuple(nestedSortEntry)) {
563
+ throw new Error(`Invalid sort definition for "${sortKey}": expected [column, direction] tuples`);
564
+ }
565
+ normalizedSorts.push(parseSortTuple(nestedSortEntry, [...path, sortKey]));
566
+ }
567
+ continue;
568
+ }
569
+ if (isPlainObject(sortEntry)) {
570
+ normalizedSorts.push(...normalizeSortObject(sortEntry, [...path, sortKey]));
571
+ continue;
572
+ }
573
+ throw new Error(`Invalid sort definition for "${sortKey}": ${typeof sortEntry}`);
574
+ }
575
+ return normalizedSorts;
672
576
  }
673
-
674
577
  /**
675
578
  * Normalize any supported sort payload into flat sort descriptors.
676
579
  * @param {?} sort - Sort payload.
677
580
  * @returns {FrontendModelSort[]} - Normalized sort definitions.
678
581
  */
679
582
  export function normalizeSort(sort) {
680
- if (!sort) return []
681
-
682
- if (typeof sort === "string") {
683
- return [parseSortString(sort)]
684
- }
685
-
686
- if (sortTuple(sort)) {
687
- return [parseSortTuple(sort)]
688
- }
689
-
690
- if (sortDescriptor(sort)) {
691
- return [{
692
- column: sort.column.trim(),
693
- direction: normalizeSortDirection(sort.direction),
694
- path: [...sort.path]
695
- }]
696
- }
697
-
698
- if (isPlainObject(sort)) {
699
- return normalizeSortObject(sort, [])
700
- }
701
-
702
- if (Array.isArray(sort)) {
703
- /**
704
- * Normalized.
705
- @type {FrontendModelSort[]} */
706
- const normalized = []
707
-
708
- for (const sortEntry of sort) {
709
- if (typeof sortEntry === "string") {
710
- normalized.push(parseSortString(sortEntry))
711
- continue
712
- }
713
-
714
- if (sortTuple(sortEntry)) {
715
- normalized.push(parseSortTuple(sortEntry))
716
- continue
717
- }
718
-
719
- if (sortDescriptor(sortEntry)) {
720
- normalized.push({
721
- column: sortEntry.column.trim(),
722
- direction: normalizeSortDirection(sortEntry.direction),
723
- path: [...sortEntry.path]
724
- })
725
- continue
726
- }
727
-
728
- if (isPlainObject(sortEntry)) {
729
- normalized.push(...normalizeSortObject(sortEntry, []))
730
- continue
731
- }
732
-
733
- throw new Error(`Invalid sort entry type: ${typeof sortEntry}`)
734
- }
735
-
736
- return normalized
737
- }
738
-
739
- throw new Error(`Invalid sort type: ${typeof sort}`)
583
+ if (!sort)
584
+ return [];
585
+ if (typeof sort === "string") {
586
+ return [parseSortString(sort)];
587
+ }
588
+ if (sortTuple(sort)) {
589
+ return [parseSortTuple(sort)];
590
+ }
591
+ if (sortDescriptor(sort)) {
592
+ return [{
593
+ column: sort.column.trim(),
594
+ direction: normalizeSortDirection(sort.direction),
595
+ path: [...sort.path]
596
+ }];
597
+ }
598
+ if (isPlainObject(sort)) {
599
+ return normalizeSortObject(sort, []);
600
+ }
601
+ if (Array.isArray(sort)) {
602
+ /**
603
+ * Normalized.
604
+ @type {FrontendModelSort[]} */
605
+ const normalized = [];
606
+ for (const sortEntry of sort) {
607
+ if (typeof sortEntry === "string") {
608
+ normalized.push(parseSortString(sortEntry));
609
+ continue;
610
+ }
611
+ if (sortTuple(sortEntry)) {
612
+ normalized.push(parseSortTuple(sortEntry));
613
+ continue;
614
+ }
615
+ if (sortDescriptor(sortEntry)) {
616
+ normalized.push({
617
+ column: sortEntry.column.trim(),
618
+ direction: normalizeSortDirection(sortEntry.direction),
619
+ path: [...sortEntry.path]
620
+ });
621
+ continue;
622
+ }
623
+ if (isPlainObject(sortEntry)) {
624
+ normalized.push(...normalizeSortObject(sortEntry, []));
625
+ continue;
626
+ }
627
+ throw new Error(`Invalid sort entry type: ${typeof sortEntry}`);
628
+ }
629
+ return normalized;
630
+ }
631
+ throw new Error(`Invalid sort type: ${typeof sort}`);
740
632
  }
741
-
742
633
  /**
743
634
  * Parse a string shorthand into a group descriptor.
744
635
  * @param {string} groupValue - Group string.
@@ -746,32 +637,31 @@ export function normalizeSort(sort) {
746
637
  * @returns {FrontendModelGroup} - Normalized group descriptor.
747
638
  */
748
639
  function parseGroupString(groupValue, path = []) {
749
- const trimmed = groupValue.trim()
750
-
751
- if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(trimmed)) {
752
- throw new Error(`Invalid group column: ${groupValue}`)
753
- }
754
-
755
- return {
756
- column: trimmed,
757
- path: [...path]
758
- }
640
+ const trimmed = groupValue.trim();
641
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(trimmed)) {
642
+ throw new Error(`Invalid group column: ${groupValue}`);
643
+ }
644
+ return {
645
+ column: trimmed,
646
+ path: [...path]
647
+ };
759
648
  }
760
-
761
649
  /**
762
650
  * Check whether a value is a structured column/path descriptor.
763
651
  * @param {?} value - Candidate descriptor.
764
652
  * @returns {value is {column: string, path: string[]}} - Whether candidate is an explicit column descriptor object.
765
653
  */
766
654
  function columnPathDescriptor(value) {
767
- if (!isPlainObject(value)) return false
768
- if (!("column" in value) || !("path" in value)) return false
769
- if (typeof value.column !== "string") return false
770
- if (!Array.isArray(value.path)) return false
771
-
772
- return value.path.every((pathEntry) => typeof pathEntry === "string")
655
+ if (!isPlainObject(value))
656
+ return false;
657
+ if (!("column" in value) || !("path" in value))
658
+ return false;
659
+ if (typeof value.column !== "string")
660
+ return false;
661
+ if (!Array.isArray(value.path))
662
+ return false;
663
+ return value.path.every((pathEntry) => typeof pathEntry === "string");
773
664
  }
774
-
775
665
  /**
776
666
  * Normalize a nested object column projection payload into flat descriptors.
777
667
  * @template {{column: string, path: string[]}} T
@@ -782,101 +672,82 @@ function columnPathDescriptor(value) {
782
672
  * @returns {T[]} - Normalized projection descriptors.
783
673
  */
784
674
  function normalizeColumnProjectionObject(value, path, parseString, label) {
785
- /**
786
- * Normalized.
787
- @type {T[]} */
788
- const normalized = []
789
-
790
- for (const [projectionKey, projectionEntry] of Object.entries(value)) {
791
- if (typeof projectionEntry === "string") {
792
- normalized.push(parseString(projectionEntry, [...path, projectionKey]))
793
- continue
794
- }
795
-
796
- if (Array.isArray(projectionEntry)) {
797
- if (projectionEntry.length < 1) {
798
- throw new Error(`Invalid ${label} definition for "${projectionKey}": empty array`)
799
- }
800
-
801
- for (const nestedProjectionEntry of projectionEntry) {
802
- if (typeof nestedProjectionEntry !== "string") {
803
- throw new Error(`Invalid ${label} definition for "${projectionKey}": expected string columns`)
804
- }
805
-
806
- normalized.push(parseString(nestedProjectionEntry, [...path, projectionKey]))
807
- }
808
-
809
- continue
810
- }
811
-
812
- if (isPlainObject(projectionEntry)) {
813
- normalized.push(...normalizeColumnProjectionObject(projectionEntry, [...path, projectionKey], parseString, label))
814
- continue
815
- }
816
-
817
- throw new Error(`Invalid ${label} definition for "${projectionKey}": ${typeof projectionEntry}`)
818
- }
819
-
820
- return normalized
675
+ /**
676
+ * Normalized.
677
+ @type {T[]} */
678
+ const normalized = [];
679
+ for (const [projectionKey, projectionEntry] of Object.entries(value)) {
680
+ if (typeof projectionEntry === "string") {
681
+ normalized.push(parseString(projectionEntry, [...path, projectionKey]));
682
+ continue;
683
+ }
684
+ if (Array.isArray(projectionEntry)) {
685
+ if (projectionEntry.length < 1) {
686
+ throw new Error(`Invalid ${label} definition for "${projectionKey}": empty array`);
687
+ }
688
+ for (const nestedProjectionEntry of projectionEntry) {
689
+ if (typeof nestedProjectionEntry !== "string") {
690
+ throw new Error(`Invalid ${label} definition for "${projectionKey}": expected string columns`);
691
+ }
692
+ normalized.push(parseString(nestedProjectionEntry, [...path, projectionKey]));
693
+ }
694
+ continue;
695
+ }
696
+ if (isPlainObject(projectionEntry)) {
697
+ normalized.push(...normalizeColumnProjectionObject(projectionEntry, [...path, projectionKey], parseString, label));
698
+ continue;
699
+ }
700
+ throw new Error(`Invalid ${label} definition for "${projectionKey}": ${typeof projectionEntry}`);
701
+ }
702
+ return normalized;
821
703
  }
822
-
823
704
  /**
824
705
  * Normalize any supported group payload into flat group descriptors.
825
706
  * @param {?} group - Group payload.
826
707
  * @returns {FrontendModelGroup[]} - Normalized group definitions.
827
708
  */
828
709
  export function normalizeGroup(group) {
829
- if (!group) return []
830
-
831
- if (typeof group === "string") {
832
- return [parseGroupString(group)]
833
- }
834
-
835
- if (columnPathDescriptor(group)) {
836
- return [{
837
- column: parseGroupString(group.column).column,
838
- path: [...group.path]
839
- }]
840
- }
841
-
842
- if (isPlainObject(group)) {
843
- return normalizeColumnProjectionObject(group, [], parseGroupString, "group")
844
- }
845
-
846
- if (Array.isArray(group)) {
847
- /**
848
- * Normalized.
849
- @type {FrontendModelGroup[]} */
850
- const normalized = []
851
-
852
- for (const groupEntry of group) {
853
- if (typeof groupEntry === "string") {
854
- normalized.push(parseGroupString(groupEntry))
855
- continue
856
- }
857
-
858
- if (columnPathDescriptor(groupEntry)) {
859
- normalized.push({
860
- column: parseGroupString(groupEntry.column).column,
861
- path: [...groupEntry.path]
862
- })
863
- continue
864
- }
865
-
866
- if (isPlainObject(groupEntry)) {
867
- normalized.push(...normalizeColumnProjectionObject(groupEntry, [], parseGroupString, "group"))
868
- continue
869
- }
870
-
871
- throw new Error(`Invalid group entry type: ${typeof groupEntry}`)
872
- }
873
-
874
- return normalized
875
- }
876
-
877
- throw new Error(`Invalid group type: ${typeof group}`)
710
+ if (!group)
711
+ return [];
712
+ if (typeof group === "string") {
713
+ return [parseGroupString(group)];
714
+ }
715
+ if (columnPathDescriptor(group)) {
716
+ return [{
717
+ column: parseGroupString(group.column).column,
718
+ path: [...group.path]
719
+ }];
720
+ }
721
+ if (isPlainObject(group)) {
722
+ return normalizeColumnProjectionObject(group, [], parseGroupString, "group");
723
+ }
724
+ if (Array.isArray(group)) {
725
+ /**
726
+ * Normalized.
727
+ @type {FrontendModelGroup[]} */
728
+ const normalized = [];
729
+ for (const groupEntry of group) {
730
+ if (typeof groupEntry === "string") {
731
+ normalized.push(parseGroupString(groupEntry));
732
+ continue;
733
+ }
734
+ if (columnPathDescriptor(groupEntry)) {
735
+ normalized.push({
736
+ column: parseGroupString(groupEntry.column).column,
737
+ path: [...groupEntry.path]
738
+ });
739
+ continue;
740
+ }
741
+ if (isPlainObject(groupEntry)) {
742
+ normalized.push(...normalizeColumnProjectionObject(groupEntry, [], parseGroupString, "group"));
743
+ continue;
744
+ }
745
+ throw new Error(`Invalid group entry type: ${typeof groupEntry}`);
746
+ }
747
+ return normalized;
748
+ }
749
+ throw new Error(`Invalid group type: ${typeof group}`);
878
750
  }
879
-
880
751
  /**
881
752
  * Parse a string shorthand into a pluck descriptor.
882
753
  * @param {string} pluckValue - Pluck string.
@@ -884,97 +755,80 @@ export function normalizeGroup(group) {
884
755
  * @returns {FrontendModelPluck} - Normalized pluck descriptor.
885
756
  */
886
757
  function parsePluckString(pluckValue, path = []) {
887
- const trimmed = pluckValue.trim()
888
-
889
- if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(trimmed)) {
890
- throw new Error(`Invalid pluck column: ${pluckValue}`)
891
- }
892
-
893
- return {
894
- column: trimmed,
895
- path: [...path]
896
- }
758
+ const trimmed = pluckValue.trim();
759
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(trimmed)) {
760
+ throw new Error(`Invalid pluck column: ${pluckValue}`);
761
+ }
762
+ return {
763
+ column: trimmed,
764
+ path: [...path]
765
+ };
897
766
  }
898
-
899
767
  /**
900
768
  * Normalize any supported pluck payload into flat pluck descriptors.
901
769
  * @param {?} pluck - Pluck payload.
902
770
  * @returns {FrontendModelPluck[]} - Normalized pluck definitions.
903
771
  */
904
772
  export function normalizePluck(pluck) {
905
- if (!pluck) return []
906
-
907
- if (typeof pluck === "string") {
908
- return [parsePluckString(pluck)]
909
- }
910
-
911
- if (columnPathDescriptor(pluck)) {
912
- return [{
913
- column: parsePluckString(pluck.column).column,
914
- path: [...pluck.path]
915
- }]
916
- }
917
-
918
- if (isPlainObject(pluck)) {
919
- return normalizeColumnProjectionObject(pluck, [], parsePluckString, "pluck")
920
- }
921
-
922
- if (Array.isArray(pluck)) {
923
- /**
924
- * Normalized.
925
- @type {FrontendModelPluck[]} */
926
- const normalized = []
927
-
928
- for (const pluckEntry of pluck) {
929
- if (typeof pluckEntry === "string") {
930
- normalized.push(parsePluckString(pluckEntry))
931
- continue
932
- }
933
-
934
- if (columnPathDescriptor(pluckEntry)) {
935
- normalized.push({
936
- column: parsePluckString(pluckEntry.column).column,
937
- path: [...pluckEntry.path]
938
- })
939
- continue
940
- }
941
-
942
- if (isPlainObject(pluckEntry)) {
943
- normalized.push(...normalizeColumnProjectionObject(pluckEntry, [], parsePluckString, "pluck"))
944
- continue
945
- }
946
-
947
- throw new Error(`Invalid pluck entry type: ${typeof pluckEntry}`)
948
- }
949
-
950
- return normalized
951
- }
952
-
953
- throw new Error(`Invalid pluck type: ${typeof pluck}`)
773
+ if (!pluck)
774
+ return [];
775
+ if (typeof pluck === "string") {
776
+ return [parsePluckString(pluck)];
777
+ }
778
+ if (columnPathDescriptor(pluck)) {
779
+ return [{
780
+ column: parsePluckString(pluck.column).column,
781
+ path: [...pluck.path]
782
+ }];
783
+ }
784
+ if (isPlainObject(pluck)) {
785
+ return normalizeColumnProjectionObject(pluck, [], parsePluckString, "pluck");
786
+ }
787
+ if (Array.isArray(pluck)) {
788
+ /**
789
+ * Normalized.
790
+ @type {FrontendModelPluck[]} */
791
+ const normalized = [];
792
+ for (const pluckEntry of pluck) {
793
+ if (typeof pluckEntry === "string") {
794
+ normalized.push(parsePluckString(pluckEntry));
795
+ continue;
796
+ }
797
+ if (columnPathDescriptor(pluckEntry)) {
798
+ normalized.push({
799
+ column: parsePluckString(pluckEntry.column).column,
800
+ path: [...pluckEntry.path]
801
+ });
802
+ continue;
803
+ }
804
+ if (isPlainObject(pluckEntry)) {
805
+ normalized.push(...normalizeColumnProjectionObject(pluckEntry, [], parsePluckString, "pluck"));
806
+ continue;
807
+ }
808
+ throw new Error(`Invalid pluck entry type: ${typeof pluckEntry}`);
809
+ }
810
+ return normalized;
811
+ }
812
+ throw new Error(`Invalid pluck type: ${typeof pluck}`);
954
813
  }
955
-
956
814
  /**
957
815
  * Runs frontend model resource attributes.
958
816
  * @param {typeof import("./base.js").default} modelClass - Model class.
959
817
  * @returns {Set<string>} - Resource attribute names.
960
818
  */
961
819
  function frontendModelResourceAttributes(modelClass) {
962
- const resourceConfig = /**
963
- * Narrows the runtime value to the documented type.
964
- @type {Record<string, ?>} */ (modelClass.resourceConfig())
965
- const attributes = resourceConfig.attributes
966
-
967
- if (Array.isArray(attributes)) {
968
- return new Set(attributes)
969
- }
970
-
971
- if (isPlainObject(attributes)) {
972
- return new Set(Object.keys(attributes))
973
- }
974
-
975
- return new Set()
820
+ const resourceConfig = /**
821
+ * Narrows the runtime value to the documented type.
822
+ @type {Record<string, ?>} */ (modelClass.resourceConfig());
823
+ const attributes = resourceConfig.attributes;
824
+ if (Array.isArray(attributes)) {
825
+ return new Set(attributes);
826
+ }
827
+ if (isPlainObject(attributes)) {
828
+ return new Set(Object.keys(attributes));
829
+ }
830
+ return new Set();
976
831
  }
977
-
978
832
  /**
979
833
  * Runs frontend model pluck target model class.
980
834
  * @param {typeof import("./base.js").default} modelClass - Root model class.
@@ -982,32 +836,26 @@ function frontendModelResourceAttributes(modelClass) {
982
836
  * @returns {typeof import("./base.js").default} - Target model class for path.
983
837
  */
984
838
  function frontendModelPluckTargetModelClass(modelClass, path) {
985
- let targetModelClass = modelClass
986
-
987
- for (const relationshipName of path) {
988
- const relationshipDefinitions = typeof targetModelClass.relationshipDefinitions === "function"
989
- ? targetModelClass.relationshipDefinitions()
990
- : {}
991
- const relationshipModelClasses = typeof targetModelClass.relationshipModelClasses === "function"
992
- ? targetModelClass.relationshipModelClasses()
993
- : {}
994
- const relationshipDefinition = relationshipDefinitions[relationshipName]
995
- const relationshipTargetModelClass = resolveFrontendModelClass(relationshipModelClasses[relationshipName])
996
-
997
- if (!relationshipDefinition) {
998
- throw new Error(`Unknown pluck relationship "${relationshipName}" for ${targetModelClass.name}`)
999
- }
1000
-
1001
- if (!relationshipTargetModelClass) {
1002
- throw new Error(`No relationship model class configured for ${targetModelClass.name}#${relationshipName}`)
1003
- }
1004
-
1005
- targetModelClass = relationshipTargetModelClass
1006
- }
1007
-
1008
- return targetModelClass
839
+ let targetModelClass = modelClass;
840
+ for (const relationshipName of path) {
841
+ const relationshipDefinitions = typeof targetModelClass.relationshipDefinitions === "function"
842
+ ? targetModelClass.relationshipDefinitions()
843
+ : {};
844
+ const relationshipModelClasses = typeof targetModelClass.relationshipModelClasses === "function"
845
+ ? targetModelClass.relationshipModelClasses()
846
+ : {};
847
+ const relationshipDefinition = relationshipDefinitions[relationshipName];
848
+ const relationshipTargetModelClass = resolveFrontendModelClass(relationshipModelClasses[relationshipName]);
849
+ if (!relationshipDefinition) {
850
+ throw new Error(`Unknown pluck relationship "${relationshipName}" for ${targetModelClass.name}`);
851
+ }
852
+ if (!relationshipTargetModelClass) {
853
+ throw new Error(`No relationship model class configured for ${targetModelClass.name}#${relationshipName}`);
854
+ }
855
+ targetModelClass = relationshipTargetModelClass;
856
+ }
857
+ return targetModelClass;
1009
858
  }
1010
-
1011
859
  /**
1012
860
  * Runs validate pluck definitions.
1013
861
  * @param {object} args - Pluck validation args.
@@ -1015,35 +863,32 @@ function frontendModelPluckTargetModelClass(modelClass, path) {
1015
863
  * @param {FrontendModelPluck[]} args.pluck - Pluck descriptors.
1016
864
  * @returns {FrontendModelPluck[]} - Validated pluck descriptors.
1017
865
  */
1018
- function validatePluckDefinitions({modelClass, pluck}) {
1019
- return pluck.map((pluckEntry) => {
1020
- const targetModelClass = frontendModelPluckTargetModelClass(modelClass, pluckEntry.path)
1021
- const targetAttributes = frontendModelResourceAttributes(targetModelClass)
1022
-
1023
- if (!targetAttributes.has(pluckEntry.column)) {
1024
- throw new Error(`Unknown pluck column "${pluckEntry.column}" for ${targetModelClass.name}`)
1025
- }
1026
-
1027
- return {
1028
- column: pluckEntry.column,
1029
- path: [...pluckEntry.path]
1030
- }
1031
- })
866
+ function validatePluckDefinitions({ modelClass, pluck }) {
867
+ return pluck.map((pluckEntry) => {
868
+ const targetModelClass = frontendModelPluckTargetModelClass(modelClass, pluckEntry.path);
869
+ const targetAttributes = frontendModelResourceAttributes(targetModelClass);
870
+ if (!targetAttributes.has(pluckEntry.column)) {
871
+ throw new Error(`Unknown pluck column "${pluckEntry.column}" for ${targetModelClass.name}`);
872
+ }
873
+ return {
874
+ column: pluckEntry.column,
875
+ path: [...pluckEntry.path]
876
+ };
877
+ });
1032
878
  }
1033
-
1034
879
  /**
1035
880
  * Runs serialize find conditions.
1036
881
  * @param {Record<string, ?>} conditions - findBy conditions.
1037
882
  * @returns {string} - Serialized conditions for error messages.
1038
883
  */
1039
884
  function serializeFindConditions(conditions) {
1040
- try {
1041
- return JSON.stringify(conditions)
1042
- } catch {
1043
- return "[unserializable conditions]"
1044
- }
885
+ try {
886
+ return JSON.stringify(conditions);
887
+ }
888
+ catch {
889
+ return "[unserializable conditions]";
890
+ }
1045
891
  }
1046
-
1047
892
  /**
1048
893
  * Runs normalize integer argument.
1049
894
  * @param {?} value - Candidate integer value.
@@ -1052,1097 +897,960 @@ function serializeFindConditions(conditions) {
1052
897
  * @param {number} options.min - Minimum allowed value.
1053
898
  * @returns {number} - Normalized integer value.
1054
899
  */
1055
- function normalizeIntegerArgument(value, argumentName, {min}) {
1056
- if (typeof value !== "number" || !Number.isInteger(value)) {
1057
- throw new Error(`${argumentName} must be an integer number`)
1058
- }
1059
-
1060
- if (value < min) {
1061
- throw new Error(`${argumentName} must be greater than or equal to ${min}`)
1062
- }
1063
-
1064
- return value
900
+ function normalizeIntegerArgument(value, argumentName, { min }) {
901
+ if (typeof value !== "number" || !Number.isInteger(value)) {
902
+ throw new Error(`${argumentName} must be an integer number`);
903
+ }
904
+ if (value < min) {
905
+ throw new Error(`${argumentName} must be greater than or equal to ${min}`);
906
+ }
907
+ return value;
1065
908
  }
1066
-
1067
909
  /**
1068
910
  * Runs reverse sort direction.
1069
911
  * @param {"asc" | "desc"} direction - Current sort direction.
1070
912
  * @returns {"asc" | "desc"} - Reversed direction.
1071
913
  */
1072
914
  function reverseSortDirection(direction) {
1073
- return direction === "asc" ? "desc" : "asc"
915
+ return direction === "asc" ? "desc" : "asc";
1074
916
  }
1075
-
1076
917
  /**
1077
918
  * Query wrapper for frontend model commands.
1078
919
  * @template {typeof import("./base.js").default} T
1079
920
  */
1080
921
  export default class FrontendModelQuery {
1081
- /**
1082
- * Ransack.
1083
- @type {Record<string, ?>[]} */
1084
- _ransack = []
1085
- /**
1086
- * Searches.
1087
- @type {FrontendModelSearch[]} */
1088
- _searches = []
1089
- /**
1090
- * Sort.
1091
- @type {FrontendModelSort[]} */
1092
- _sort = []
1093
- /**
1094
- * Group.
1095
- @type {FrontendModelGroup[]} */
1096
- _group = []
1097
-
1098
- /**
1099
- * Runs constructor.
1100
- * @param {object} args - Constructor args.
1101
- * @param {T} args.modelClass - Frontend model class.
1102
- * @param {import("../database/query/index.js").NestedPreloadRecord} [args.preload] - Preload map.
1103
- */
1104
- constructor({modelClass, preload = {}}) {
1105
- this.modelClass = modelClass
1106
- this._preload = normalizePreload(preload)
1107
- this._joins = {}
1108
- this._where = {}
1109
- this._searches = []
1110
- /**
1111
- * Narrows the runtime value to the documented type.
1112
- @type {Record<string, string[]>} */
1113
- this._select = {}
1114
922
  /**
1115
- * Narrows the runtime value to the documented type.
1116
- @type {Record<string, string[]>} */
1117
- this._selectsExtra = {}
1118
- this._sort = []
1119
- this._group = []
1120
- this._distinct = false
1121
- this._limit = null
1122
- this._offset = null
1123
- this._page = null
1124
- this._perPage = null
1125
- /**
1126
- * Narrows the runtime value to the documented type.
1127
- @type {Array<{attributeName: string, relationshipName: string, where?: Record<string, ?>}>} */
1128
- this._withCount = []
1129
- /**
1130
- * Narrows the runtime value to the documented type.
1131
- @type {Array<string | Record<string, ?>>} */
1132
- this._queryData = []
1133
- /**
1134
- * Per-record ability spec. Normalized to a list of
1135
- * `{modelName, actions}` entries — one entry per model that should
1136
- * have ability results attached. The root query's model class
1137
- * name is implicit via `"__root__"` when the caller used the flat
1138
- * array form.
1139
- * @type {Array<{modelName: string, actions: string[]}>}
923
+ * Ransack.
924
+ @type {Record<string, ?>[]} */
925
+ _ransack = [];
926
+ /**
927
+ * Searches.
928
+ @type {FrontendModelSearch[]} */
929
+ _searches = [];
930
+ /**
931
+ * Sort.
932
+ @type {FrontendModelSort[]} */
933
+ _sort = [];
934
+ /**
935
+ * Group.
936
+ @type {FrontendModelGroup[]} */
937
+ _group = [];
938
+ /**
939
+ * Runs constructor.
940
+ * @param {object} args - Constructor args.
941
+ * @param {T} args.modelClass - Frontend model class.
942
+ * @param {import("../database/query/index.js").NestedPreloadRecord} [args.preload] - Preload map.
943
+ */
944
+ constructor({ modelClass, preload = {} }) {
945
+ this.modelClass = modelClass;
946
+ this._preload = normalizePreload(preload);
947
+ this._joins = {};
948
+ this._where = {};
949
+ this._searches = [];
950
+ /**
951
+ * Narrows the runtime value to the documented type.
952
+ @type {Record<string, string[]>} */
953
+ this._select = {};
954
+ /**
955
+ * Narrows the runtime value to the documented type.
956
+ @type {Record<string, string[]>} */
957
+ this._selectsExtra = {};
958
+ this._sort = [];
959
+ this._group = [];
960
+ this._distinct = false;
961
+ this._limit = null;
962
+ this._offset = null;
963
+ this._page = null;
964
+ this._perPage = null;
965
+ /**
966
+ * Narrows the runtime value to the documented type.
967
+ @type {Array<{attributeName: string, relationshipName: string, where?: Record<string, ?>}>} */
968
+ this._withCount = [];
969
+ /**
970
+ * Narrows the runtime value to the documented type.
971
+ @type {Array<string | Record<string, ?>>} */
972
+ this._queryData = [];
973
+ /**
974
+ * Per-record ability spec. Normalized to a list of
975
+ * `{modelName, actions}` entries — one entry per model that should
976
+ * have ability results attached. The root query's model class
977
+ * name is implicit via `"__root__"` when the caller used the flat
978
+ * array form.
979
+ * @type {Array<{modelName: string, actions: string[]}>}
980
+ */
981
+ this._abilities = [];
982
+ }
983
+ /**
984
+ * Tell the backend to evaluate one or more ability actions against
985
+ * each returned record (and its preloaded relations, when keyed by
986
+ * model name) and ship the results back so the frontend can read
987
+ * them via `record.can(action)`.
988
+ *
989
+ * Flat form — applies to the query's own model class:
990
+ * ```
991
+ * const timelogs = await Timelog.where({taskId})
992
+ * .abilities(["update", "destroy"])
993
+ * .toArray()
994
+ * timelogs[0].can("update") // → boolean
995
+ * ```
996
+ *
997
+ * Keyed form — targets records by model name, useful for preloaded
998
+ * children:
999
+ * ```
1000
+ * const project = await Project
1001
+ * .preload("timelogs")
1002
+ * .abilities({Timelog: ["update", "destroy"]})
1003
+ * .first()
1004
+ * project.timelogs().loaded()[0].can("update") // → boolean
1005
+ * ```
1006
+ *
1007
+ * Keys in the keyed form are the backend model names (as returned by
1008
+ * `ModelClass.getModelName()` / the `modelName` field of the
1009
+ * frontend-model resource config). Values are the ability-action
1010
+ * strings — typically `"update"` / `"destroy"` / `"create"` /
1011
+ * `"read"`, but any custom action registered on the resource's
1012
+ * authorization ability is accepted.
1013
+ * @param {string[] | Record<string, string[]>} spec
1014
+ * @returns {this}
1015
+ */
1016
+ abilities(spec) {
1017
+ for (const entry of normalizeAbilitiesSpec(spec, this.modelClass)) {
1018
+ this._mergeAbilityEntry(entry);
1019
+ }
1020
+ return this;
1021
+ }
1022
+ /**
1023
+ * Runs merge ability entry.
1024
+ * @param {{modelName: string, actions: string[]}} entry
1025
+ * @returns {void}
1026
+ */
1027
+ _mergeAbilityEntry(entry) {
1028
+ const existing = this._abilities.find((candidate) => candidate.modelName === entry.modelName);
1029
+ if (!existing) {
1030
+ this._abilities.push({ actions: [...entry.actions], modelName: entry.modelName });
1031
+ return;
1032
+ }
1033
+ for (const action of entry.actions) {
1034
+ if (!existing.actions.includes(action))
1035
+ existing.actions.push(action);
1036
+ }
1037
+ }
1038
+ /**
1039
+ * Tell the backend index query to attach one or more association
1040
+ * counts to each returned record. Parses the same shapes as the
1041
+ * backend `ModelClassQuery#withCount`, then ships the normalized
1042
+ * entries as part of the `index` command payload.
1043
+ * @param {string | string[] | Record<string, boolean | {relationship?: string, where?: Record<string, ?>}>} spec
1044
+ * @returns {this}
1045
+ */
1046
+ withCount(spec) {
1047
+ for (const entry of normalizeWithCountFrontend(spec)) {
1048
+ this._withCount.push(entry);
1049
+ }
1050
+ return this;
1051
+ }
1052
+ /**
1053
+ * Request one or more backend queryData entries for each returned
1054
+ * record. The spec is a name or nested-record shape matching the
1055
+ * `Model.queryData(name, fn)` registrations on the backend — the
1056
+ * frontend ships only these names; the SQL fragments stay server-
1057
+ * side. All resulting aliases are attached to the root record and
1058
+ * read back with `record.queryData(aliasName)`.
1059
+ * @param {string | Array<string | Record<string, ?>> | Record<string, ?>} spec
1060
+ * @returns {this}
1061
+ */
1062
+ queryData(spec) {
1063
+ if (spec == null)
1064
+ return this;
1065
+ this._queryData.push(/**
1066
+ * Narrows the runtime value to the documented type.
1067
+ @type {?} */ (spec));
1068
+ return this;
1069
+ }
1070
+ /**
1071
+ * Runs where.
1072
+ * @param {Record<string, ?>} conditions - Root-model where conditions.
1073
+ * @returns {this} - Query with merged where conditions.
1074
+ */
1075
+ where(conditions) {
1076
+ this.modelClass.assertFindByConditions(conditions);
1077
+ this._where = {
1078
+ ...this._where,
1079
+ ...conditions
1080
+ };
1081
+ return this;
1082
+ }
1083
+ /**
1084
+ * Runs scope.
1085
+ * @param {import("../utils/model-scope.js").ModelScopeDescriptor} scopeDescriptor - Scope descriptor.
1086
+ * @returns {this} - Scoped query.
1087
+ */
1088
+ scope(scopeDescriptor) {
1089
+ if (!isModelScopeDescriptor(scopeDescriptor)) {
1090
+ throw new Error("scope() expects a descriptor returned by defineScope(...).scope(...)");
1091
+ }
1092
+ if (scopeDescriptor.modelClass !== this.modelClass) {
1093
+ throw new Error(`Cannot apply ${scopeDescriptor.modelClass.name} scope to ${this.modelClass.name} query`);
1094
+ }
1095
+ const scopedQuery = /**
1096
+ * Narrows the runtime value to the documented type.
1097
+ @type {this | void} */ (scopeDescriptor.callback({
1098
+ driver: null,
1099
+ modelClass: this.modelClass,
1100
+ query: this,
1101
+ table: null
1102
+ }, ...scopeDescriptor.scopeArgs));
1103
+ return scopedQuery || this;
1104
+ }
1105
+ /**
1106
+ * Runs ransack.
1107
+ * @param {Record<string, ?>} params - Ransack-style params hash. Supports `s` key for sorting (e.g., `{s: "name asc"}`).
1108
+ * @returns {this} - Query with Ransack filters and sort applied.
1109
+ */
1110
+ ransack(params) {
1111
+ const { s, ...filterParams } = params;
1112
+ const hasFilters = Object.keys(filterParams).length > 0;
1113
+ if (hasFilters) {
1114
+ normalizeRansackGroup(this.modelClass, filterParams);
1115
+ this._ransack.push(filterParams);
1116
+ }
1117
+ if (typeof s === "string" && s.trim().length > 0) {
1118
+ const sorts = parseRansackSort(this.modelClass, s);
1119
+ for (const sortDef of sorts) {
1120
+ this.sort([[sortDef.attribute, sortDef.direction]]);
1121
+ }
1122
+ }
1123
+ return this;
1124
+ }
1125
+ /**
1126
+ * Runs select with required root attributes.
1127
+ * @param {string[]} [requiredAttributes] - Extra required attributes for the root model.
1128
+ * @returns {Record<string, string[]>} - Select map with required root attributes merged when root select exists.
1129
+ */
1130
+ selectWithRequiredRootAttributes(requiredAttributes = []) {
1131
+ const rootModelName = this.modelClass.getModelName();
1132
+ const selectMap = /**
1133
+ * Narrows the runtime value to the documented type.
1134
+ @type {Record<string, string[]>} */ (this._select);
1135
+ const existingRootAttributes = selectMap[rootModelName];
1136
+ if (!existingRootAttributes) {
1137
+ return selectMap;
1138
+ }
1139
+ const rootPrimaryKey = this.modelClass.primaryKey();
1140
+ return {
1141
+ ...selectMap,
1142
+ [rootModelName]: Array.from(new Set([rootPrimaryKey, ...existingRootAttributes, ...requiredAttributes]))
1143
+ };
1144
+ }
1145
+ /**
1146
+ * Runs preload.
1147
+ * @param {import("../database/query/index.js").NestedPreloadRecord | string | Array<string | import("../database/query/index.js").NestedPreloadRecord>} preload - Preload to merge.
1148
+ * @returns {this} - Query with merged preloads.
1149
+ */
1150
+ preload(preload) {
1151
+ mergePreloadRecord(this._preload, normalizePreload(preload));
1152
+ return this;
1153
+ }
1154
+ /**
1155
+ * Runs select.
1156
+ * @param {Record<string, string[] | string> | string | string[]} select - Model-aware attribute select map or root-model shorthand.
1157
+ * @returns {this} - Query with merged selected attributes.
1158
+ */
1159
+ select(select) {
1160
+ mergeSelectRecord(this._select, normalizeSelect(select, this.modelClass.getModelName()));
1161
+ return this;
1162
+ }
1163
+ /**
1164
+ * Like `select(...)`, but keeps the default serialized attributes and loads
1165
+ * the given extras in addition (for example attributes declared
1166
+ * `selectedByDefault: false`). Keyed by model name, with root-model shorthand.
1167
+ * @param {Record<string, string[] | string> | string | string[]} select - Extra attributes to load, keyed by model name or root-model shorthand.
1168
+ * @returns {this} - Query with merged extra selected attributes.
1169
+ */
1170
+ selectsExtra(select) {
1171
+ mergeSelectRecord(this._selectsExtra, normalizeSelect(select, this.modelClass.getModelName()));
1172
+ return this;
1173
+ }
1174
+ /**
1175
+ * Runs joins.
1176
+ * @param {Record<string, ?> | Array<Record<string, ?>>} joins - Relationship descriptor joins.
1177
+ * @returns {this} - Query with merged joins.
1178
+ */
1179
+ joins(joins) {
1180
+ mergeJoinRecord(this._joins, normalizeJoins(joins));
1181
+ return this;
1182
+ }
1183
+ /**
1184
+ * Returns the search result.
1185
+ * @param {string[]} path - Relationship path.
1186
+ * @param {string} column - Column or attribute name.
1187
+ * @param {"eq" | "like" | "notEq" | "gt" | "gteq" | "lt" | "lteq" | ">" | ">=" | "<" | "<="} operator - Search operator.
1188
+ * @param {?} value - Search value.
1189
+ * @returns {this} - Query with appended search.
1190
+ */
1191
+ search(path, column, operator, value) {
1192
+ if (!Array.isArray(path)) {
1193
+ throw new Error(`search path must be an array, got: ${typeof path}`);
1194
+ }
1195
+ for (const pathEntry of path) {
1196
+ if (typeof pathEntry !== "string" || pathEntry.length < 1) {
1197
+ throw new Error("search path entries must be non-empty strings");
1198
+ }
1199
+ }
1200
+ if (typeof column !== "string" || column.length < 1) {
1201
+ throw new Error("search column must be a non-empty string");
1202
+ }
1203
+ if (typeof operator !== "string" || operator.length < 1) {
1204
+ throw new Error("search operator must be a non-empty string");
1205
+ }
1206
+ const normalizedOperator = normalizeSearchOperator(operator);
1207
+ this._searches.push({
1208
+ column,
1209
+ operator: normalizedOperator,
1210
+ path: [...path],
1211
+ value
1212
+ });
1213
+ return this;
1214
+ }
1215
+ /**
1216
+ * Runs sort.
1217
+ * @param {string | string[] | [string, string] | Array<[string, string]> | Record<string, ?> | Array<Record<string, ?>>} sort - Sort definition(s).
1218
+ * @returns {this} - Query with appended sort definitions.
1219
+ */
1220
+ sort(sort) {
1221
+ this._sort.push(...normalizeSort(sort));
1222
+ return this;
1223
+ }
1224
+ /**
1225
+ * Runs order.
1226
+ * @param {string | string[] | [string, string] | Array<[string, string]> | Record<string, ?> | Array<Record<string, ?>>} order - Order definition(s).
1227
+ * @returns {this} - Query with appended sort definitions.
1228
+ */
1229
+ order(order) {
1230
+ return this.sort(order);
1231
+ }
1232
+ /**
1233
+ * Runs group.
1234
+ * @param {string | string[] | Record<string, ?> | Array<Record<string, ?>>} group - Group definition(s).
1235
+ * @returns {this} - Query with appended group definitions.
1236
+ */
1237
+ group(group) {
1238
+ this._group.push(...normalizeGroup(group));
1239
+ return this;
1240
+ }
1241
+ /**
1242
+ * Runs distinct.
1243
+ * @param {boolean} [value] - Whether to request distinct rows.
1244
+ * @returns {this} - Query with distinct flag.
1245
+ */
1246
+ distinct(value = true) {
1247
+ if (typeof value !== "boolean") {
1248
+ throw new Error(`distinct must be a boolean, got: ${typeof value}`);
1249
+ }
1250
+ this._distinct = value;
1251
+ return this;
1252
+ }
1253
+ /**
1254
+ * Returns the limit result.
1255
+ * @param {number} value - Maximum number of records.
1256
+ * @returns {this} - Query with limit.
1257
+ */
1258
+ limit(value) {
1259
+ this._limit = normalizeIntegerArgument(value, "limit", { min: 0 });
1260
+ this._page = null;
1261
+ return this;
1262
+ }
1263
+ /**
1264
+ * Runs offset.
1265
+ * @param {number} value - Number of records to skip.
1266
+ * @returns {this} - Query with offset.
1267
+ */
1268
+ offset(value) {
1269
+ this._offset = normalizeIntegerArgument(value, "offset", { min: 0 });
1270
+ this._page = null;
1271
+ return this;
1272
+ }
1273
+ /**
1274
+ * Runs page.
1275
+ * @param {number} pageNumber - 1-based page number.
1276
+ * @returns {this} - Query with page applied.
1277
+ */
1278
+ page(pageNumber) {
1279
+ this._page = normalizeIntegerArgument(pageNumber, "page", { min: 1 });
1280
+ const pageSize = this._perPage || 30;
1281
+ this._limit = pageSize;
1282
+ this._offset = (this._page - 1) * pageSize;
1283
+ return this;
1284
+ }
1285
+ /**
1286
+ * Runs per page.
1287
+ * @param {number} perPage - Page size.
1288
+ * @returns {this} - Query with per-page applied.
1289
+ */
1290
+ perPage(perPage) {
1291
+ this._perPage = normalizeIntegerArgument(perPage, "perPage", { min: 1 });
1292
+ if (this._page !== null) {
1293
+ this._limit = this._perPage;
1294
+ this._offset = (this._page - 1) * this._perPage;
1295
+ }
1296
+ return this;
1297
+ }
1298
+ /**
1299
+ * Runs clone.
1300
+ * @returns {FrontendModelQuery<T>} - Cloned query instance.
1140
1301
  */
1141
- this._abilities = []
1142
- }
1143
-
1144
- /**
1145
- * Tell the backend to evaluate one or more ability actions against
1146
- * each returned record (and its preloaded relations, when keyed by
1147
- * model name) and ship the results back so the frontend can read
1148
- * them via `record.can(action)`.
1149
- *
1150
- * Flat form — applies to the query's own model class:
1151
- * ```
1152
- * const timelogs = await Timelog.where({taskId})
1153
- * .abilities(["update", "destroy"])
1154
- * .toArray()
1155
- * timelogs[0].can("update") // → boolean
1156
- * ```
1157
- *
1158
- * Keyed form — targets records by model name, useful for preloaded
1159
- * children:
1160
- * ```
1161
- * const project = await Project
1162
- * .preload("timelogs")
1163
- * .abilities({Timelog: ["update", "destroy"]})
1164
- * .first()
1165
- * project.timelogs().loaded()[0].can("update") // → boolean
1166
- * ```
1167
- *
1168
- * Keys in the keyed form are the backend model names (as returned by
1169
- * `ModelClass.getModelName()` / the `modelName` field of the
1170
- * frontend-model resource config). Values are the ability-action
1171
- * strings — typically `"update"` / `"destroy"` / `"create"` /
1172
- * `"read"`, but any custom action registered on the resource's
1173
- * authorization ability is accepted.
1174
- * @param {string[] | Record<string, string[]>} spec
1175
- * @returns {this}
1176
- */
1177
- abilities(spec) {
1178
- for (const entry of normalizeAbilitiesSpec(spec, this.modelClass)) {
1179
- this._mergeAbilityEntry(entry)
1180
- }
1181
-
1182
- return this
1183
- }
1184
-
1185
- /**
1186
- * Runs merge ability entry.
1187
- * @param {{modelName: string, actions: string[]}} entry
1188
- * @returns {void}
1189
- */
1190
- _mergeAbilityEntry(entry) {
1191
- const existing = this._abilities.find((candidate) => candidate.modelName === entry.modelName)
1192
-
1193
- if (!existing) {
1194
- this._abilities.push({actions: [...entry.actions], modelName: entry.modelName})
1195
- return
1196
- }
1197
-
1198
- for (const action of entry.actions) {
1199
- if (!existing.actions.includes(action)) existing.actions.push(action)
1200
- }
1201
- }
1202
-
1203
- /**
1204
- * Tell the backend index query to attach one or more association
1205
- * counts to each returned record. Parses the same shapes as the
1206
- * backend `ModelClassQuery#withCount`, then ships the normalized
1207
- * entries as part of the `index` command payload.
1208
- * @param {string | string[] | Record<string, boolean | {relationship?: string, where?: Record<string, ?>}>} spec
1209
- * @returns {this}
1210
- */
1211
- withCount(spec) {
1212
- for (const entry of normalizeWithCountFrontend(spec)) {
1213
- this._withCount.push(entry)
1214
- }
1215
-
1216
- return this
1217
- }
1218
-
1219
- /**
1220
- * Request one or more backend queryData entries for each returned
1221
- * record. The spec is a name or nested-record shape matching the
1222
- * `Model.queryData(name, fn)` registrations on the backend — the
1223
- * frontend ships only these names; the SQL fragments stay server-
1224
- * side. All resulting aliases are attached to the root record and
1225
- * read back with `record.queryData(aliasName)`.
1226
- * @param {string | Array<string | Record<string, ?>> | Record<string, ?>} spec
1227
- * @returns {this}
1228
- */
1229
- queryData(spec) {
1230
- if (spec == null) return this
1231
-
1232
- this._queryData.push(/**
1302
+ clone() {
1303
+ const newQuery = /**
1233
1304
  * Narrows the runtime value to the documented type.
1234
- @type {?} */ (spec))
1235
-
1236
- return this
1237
- }
1238
-
1239
- /**
1240
- * Runs where.
1241
- * @param {Record<string, ?>} conditions - Root-model where conditions.
1242
- * @returns {this} - Query with merged where conditions.
1243
- */
1244
- where(conditions) {
1245
- this.modelClass.assertFindByConditions(conditions)
1246
-
1247
- this._where = {
1248
- ...this._where,
1249
- ...conditions
1250
- }
1251
-
1252
- return this
1253
- }
1254
-
1255
- /**
1256
- * Runs scope.
1257
- * @param {import("../utils/model-scope.js").ModelScopeDescriptor} scopeDescriptor - Scope descriptor.
1258
- * @returns {this} - Scoped query.
1259
- */
1260
- scope(scopeDescriptor) {
1261
- if (!isModelScopeDescriptor(scopeDescriptor)) {
1262
- throw new Error("scope() expects a descriptor returned by defineScope(...).scope(...)")
1263
- }
1264
-
1265
- if (scopeDescriptor.modelClass !== this.modelClass) {
1266
- throw new Error(`Cannot apply ${scopeDescriptor.modelClass.name} scope to ${this.modelClass.name} query`)
1267
- }
1268
-
1269
- const scopedQuery = /**
1270
- * Narrows the runtime value to the documented type.
1271
- @type {this | void} */ (scopeDescriptor.callback({
1272
- driver: null,
1273
- modelClass: this.modelClass,
1274
- query: this,
1275
- table: null
1276
- }, ...scopeDescriptor.scopeArgs))
1277
-
1278
- return scopedQuery || this
1279
- }
1280
-
1281
- /**
1282
- * Runs ransack.
1283
- * @param {Record<string, ?>} params - Ransack-style params hash. Supports `s` key for sorting (e.g., `{s: "name asc"}`).
1284
- * @returns {this} - Query with Ransack filters and sort applied.
1285
- */
1286
- ransack(params) {
1287
- const {s, ...filterParams} = params
1288
- const hasFilters = Object.keys(filterParams).length > 0
1289
-
1290
- if (hasFilters) {
1291
- normalizeRansackGroup(this.modelClass, filterParams)
1292
- this._ransack.push(filterParams)
1293
- }
1294
-
1295
- if (typeof s === "string" && s.trim().length > 0) {
1296
- const sorts = parseRansackSort(this.modelClass, s)
1297
-
1298
- for (const sortDef of sorts) {
1299
- this.sort([[sortDef.attribute, sortDef.direction]])
1300
- }
1301
- }
1302
-
1303
- return this
1304
- }
1305
-
1306
- /**
1307
- * Runs select with required root attributes.
1308
- * @param {string[]} [requiredAttributes] - Extra required attributes for the root model.
1309
- * @returns {Record<string, string[]>} - Select map with required root attributes merged when root select exists.
1310
- */
1311
- selectWithRequiredRootAttributes(requiredAttributes = []) {
1312
- const rootModelName = this.modelClass.getModelName()
1313
- const selectMap = /**
1314
- * Narrows the runtime value to the documented type.
1315
- @type {Record<string, string[]>} */ (this._select)
1316
- const existingRootAttributes = selectMap[rootModelName]
1317
-
1318
- if (!existingRootAttributes) {
1319
- return selectMap
1320
- }
1321
-
1322
- const rootPrimaryKey = this.modelClass.primaryKey()
1323
-
1324
- return {
1325
- ...selectMap,
1326
- [rootModelName]: Array.from(new Set([rootPrimaryKey, ...existingRootAttributes, ...requiredAttributes]))
1327
- }
1328
- }
1329
-
1330
- /**
1331
- * Runs preload.
1332
- * @param {import("../database/query/index.js").NestedPreloadRecord | string | Array<string | import("../database/query/index.js").NestedPreloadRecord>} preload - Preload to merge.
1333
- * @returns {this} - Query with merged preloads.
1334
- */
1335
- preload(preload) {
1336
- mergePreloadRecord(this._preload, normalizePreload(preload))
1337
-
1338
- return this
1339
- }
1340
-
1341
- /**
1342
- * Runs select.
1343
- * @param {Record<string, string[] | string> | string | string[]} select - Model-aware attribute select map or root-model shorthand.
1344
- * @returns {this} - Query with merged selected attributes.
1345
- */
1346
- select(select) {
1347
- mergeSelectRecord(this._select, normalizeSelect(select, this.modelClass.getModelName()))
1348
-
1349
- return this
1350
- }
1351
-
1352
- /**
1353
- * Like `select(...)`, but keeps the default serialized attributes and loads
1354
- * the given extras in addition (for example attributes declared
1355
- * `selectedByDefault: false`). Keyed by model name, with root-model shorthand.
1356
- * @param {Record<string, string[] | string> | string | string[]} select - Extra attributes to load, keyed by model name or root-model shorthand.
1357
- * @returns {this} - Query with merged extra selected attributes.
1358
- */
1359
- selectsExtra(select) {
1360
- mergeSelectRecord(this._selectsExtra, normalizeSelect(select, this.modelClass.getModelName()))
1361
-
1362
- return this
1363
- }
1364
-
1365
- /**
1366
- * Runs joins.
1367
- * @param {Record<string, ?> | Array<Record<string, ?>>} joins - Relationship descriptor joins.
1368
- * @returns {this} - Query with merged joins.
1369
- */
1370
- joins(joins) {
1371
- mergeJoinRecord(this._joins, normalizeJoins(joins))
1372
-
1373
- return this
1374
- }
1375
-
1376
- /**
1377
- * Returns the search result.
1378
- * @param {string[]} path - Relationship path.
1379
- * @param {string} column - Column or attribute name.
1380
- * @param {"eq" | "like" | "notEq" | "gt" | "gteq" | "lt" | "lteq" | ">" | ">=" | "<" | "<="} operator - Search operator.
1381
- * @param {?} value - Search value.
1382
- * @returns {this} - Query with appended search.
1383
- */
1384
- search(path, column, operator, value) {
1385
- if (!Array.isArray(path)) {
1386
- throw new Error(`search path must be an array, got: ${typeof path}`)
1387
- }
1388
-
1389
- for (const pathEntry of path) {
1390
- if (typeof pathEntry !== "string" || pathEntry.length < 1) {
1391
- throw new Error("search path entries must be non-empty strings")
1392
- }
1393
- }
1394
-
1395
- if (typeof column !== "string" || column.length < 1) {
1396
- throw new Error("search column must be a non-empty string")
1397
- }
1398
-
1399
- if (typeof operator !== "string" || operator.length < 1) {
1400
- throw new Error("search operator must be a non-empty string")
1401
- }
1402
-
1403
- const normalizedOperator = normalizeSearchOperator(operator)
1404
-
1405
- this._searches.push({
1406
- column,
1407
- operator: normalizedOperator,
1408
- path: [...path],
1409
- value
1410
- })
1411
-
1412
- return this
1413
- }
1414
-
1415
- /**
1416
- * Runs sort.
1417
- * @param {string | string[] | [string, string] | Array<[string, string]> | Record<string, ?> | Array<Record<string, ?>>} sort - Sort definition(s).
1418
- * @returns {this} - Query with appended sort definitions.
1419
- */
1420
- sort(sort) {
1421
- this._sort.push(...normalizeSort(sort))
1422
-
1423
- return this
1424
- }
1425
-
1426
- /**
1427
- * Runs order.
1428
- * @param {string | string[] | [string, string] | Array<[string, string]> | Record<string, ?> | Array<Record<string, ?>>} order - Order definition(s).
1429
- * @returns {this} - Query with appended sort definitions.
1430
- */
1431
- order(order) {
1432
- return this.sort(order)
1433
- }
1434
-
1435
- /**
1436
- * Runs group.
1437
- * @param {string | string[] | Record<string, ?> | Array<Record<string, ?>>} group - Group definition(s).
1438
- * @returns {this} - Query with appended group definitions.
1439
- */
1440
- group(group) {
1441
- this._group.push(...normalizeGroup(group))
1442
-
1443
- return this
1444
- }
1445
-
1446
- /**
1447
- * Runs distinct.
1448
- * @param {boolean} [value] - Whether to request distinct rows.
1449
- * @returns {this} - Query with distinct flag.
1450
- */
1451
- distinct(value = true) {
1452
- if (typeof value !== "boolean") {
1453
- throw new Error(`distinct must be a boolean, got: ${typeof value}`)
1454
- }
1455
-
1456
- this._distinct = value
1457
-
1458
- return this
1459
- }
1460
-
1461
- /**
1462
- * Returns the limit result.
1463
- * @param {number} value - Maximum number of records.
1464
- * @returns {this} - Query with limit.
1465
- */
1466
- limit(value) {
1467
- this._limit = normalizeIntegerArgument(value, "limit", {min: 0})
1468
- this._page = null
1469
-
1470
- return this
1471
- }
1472
-
1473
- /**
1474
- * Runs offset.
1475
- * @param {number} value - Number of records to skip.
1476
- * @returns {this} - Query with offset.
1477
- */
1478
- offset(value) {
1479
- this._offset = normalizeIntegerArgument(value, "offset", {min: 0})
1480
- this._page = null
1481
-
1482
- return this
1483
- }
1484
-
1485
- /**
1486
- * Runs page.
1487
- * @param {number} pageNumber - 1-based page number.
1488
- * @returns {this} - Query with page applied.
1489
- */
1490
- page(pageNumber) {
1491
- this._page = normalizeIntegerArgument(pageNumber, "page", {min: 1})
1492
- const pageSize = this._perPage || 30
1493
-
1494
- this._limit = pageSize
1495
- this._offset = (this._page - 1) * pageSize
1496
-
1497
- return this
1498
- }
1499
-
1500
- /**
1501
- * Runs per page.
1502
- * @param {number} perPage - Page size.
1503
- * @returns {this} - Query with per-page applied.
1504
- */
1505
- perPage(perPage) {
1506
- this._perPage = normalizeIntegerArgument(perPage, "perPage", {min: 1})
1507
-
1508
- if (this._page !== null) {
1509
- this._limit = this._perPage
1510
- this._offset = (this._page - 1) * this._perPage
1511
- }
1512
-
1513
- return this
1514
- }
1515
-
1516
- /**
1517
- * Runs clone.
1518
- * @returns {FrontendModelQuery<T>} - Cloned query instance.
1519
- */
1520
- clone() {
1521
- const newQuery = /**
1522
- * Narrows the runtime value to the documented type.
1523
- @type {FrontendModelQuery<T>} */ (new FrontendModelQuery({
1524
- modelClass: this.modelClass,
1525
- preload: normalizePreload(this._preload)
1526
- }))
1527
-
1528
- newQuery._joins = normalizeJoins(this._joins)
1529
- newQuery._where = {...this._where}
1530
- newQuery._ransack = this._ransack.map((ransackParams) => ({...ransackParams}))
1531
- newQuery._searches = this._searches.map((search) => ({
1532
- column: search.column,
1533
- operator: search.operator,
1534
- path: [...search.path],
1535
- value: search.value
1536
- }))
1537
- newQuery._select = normalizeSelect(this._select)
1538
- newQuery._selectsExtra = normalizeSelect(this._selectsExtra)
1539
- newQuery._sort = this._sort.map((sortEntry) => ({
1540
- column: sortEntry.column,
1541
- direction: sortEntry.direction,
1542
- path: [...sortEntry.path]
1543
- }))
1544
- newQuery._group = this._group.map((groupEntry) => ({
1545
- column: groupEntry.column,
1546
- path: [...groupEntry.path]
1547
- }))
1548
- newQuery._distinct = this._distinct
1549
- newQuery._limit = this._limit
1550
- newQuery._offset = this._offset
1551
- newQuery._page = this._page
1552
- newQuery._perPage = this._perPage
1553
- newQuery._withCount = this._withCount.map((entry) => ({
1554
- attributeName: entry.attributeName,
1555
- relationshipName: entry.relationshipName,
1556
- where: entry.where ? {...entry.where} : undefined
1557
- }))
1558
- newQuery._queryData = this._queryData.map((entry) => (
1559
- typeof entry === "string" ? entry : {...entry}
1560
- ))
1561
- newQuery._abilities = this._abilities.map((entry) => ({
1562
- actions: [...entry.actions],
1563
- modelName: entry.modelName
1564
- }))
1565
-
1566
- return newQuery
1567
- }
1568
-
1569
- /**
1570
- * Runs get model class.
1571
- * @returns {T} - Root model class.
1572
- */
1573
- getModelClass() {
1574
- return this.modelClass
1575
- }
1576
-
1577
- /**
1578
- * Runs preload payload.
1579
- * @returns {Record<string, ?>} - Payload preload hash when present.
1580
- */
1581
- preloadPayload() {
1582
- if (Object.keys(this._preload).length === 0) return {}
1583
-
1584
- return {preload: this._preload}
1585
- }
1586
-
1587
- /**
1588
- * Runs with count payload.
1589
- * @returns {Record<string, ?>} - Payload withCount array when present.
1590
- */
1591
- withCountPayload() {
1592
- if (this._withCount.length === 0) return {}
1593
-
1594
- return {
1595
- withCount: this._withCount.map((entry) => ({
1596
- attributeName: entry.attributeName,
1597
- relationshipName: entry.relationshipName,
1598
- where: entry.where || undefined
1599
- }))
1600
- }
1601
- }
1602
-
1603
- /**
1604
- * Runs abilities payload.
1605
- * @returns {Record<string, ?>} - Payload abilities array when present.
1606
- */
1607
- abilitiesPayload() {
1608
- if (this._abilities.length === 0) return {}
1609
-
1610
- return {
1611
- abilities: this._abilities.map((entry) => ({
1612
- actions: [...entry.actions],
1613
- modelName: entry.modelName
1614
- }))
1615
- }
1616
- }
1617
-
1618
- /**
1619
- * Runs query data payload.
1620
- * @returns {Record<string, ?>} - Payload queryData spec when present.
1621
- */
1622
- queryDataPayload() {
1623
- if (this._queryData.length === 0) return {}
1624
-
1625
- // Single accumulated spec goes on the wire verbatim. The backend
1626
- // normalizer accepts string/array/object at each level, so we can
1627
- // ship multiple `.queryData(...)` calls as an array.
1628
- return {
1629
- queryData: this._queryData.length === 1 ? this._queryData[0] : this._queryData
1630
- }
1631
- }
1632
-
1633
- /**
1634
- * Runs select payload.
1635
- * @param {string[]} [requiredAttributes] - Extra required attributes for root model selection.
1636
- * @returns {Record<string, ?>} - Payload select hash when present.
1637
- */
1638
- selectPayload(requiredAttributes = []) {
1639
- const select = this.selectWithRequiredRootAttributes(requiredAttributes)
1640
-
1641
- if (Object.keys(select).length === 0) return {}
1642
-
1643
- return {select}
1644
- }
1645
-
1646
- /**
1647
- * Runs selects extra payload.
1648
- * @returns {Record<string, ?>} - Payload selectsExtra hash when present.
1649
- */
1650
- selectsExtraPayload() {
1651
- if (Object.keys(this._selectsExtra).length === 0) return {}
1652
-
1653
- return {selectsExtra: this._selectsExtra}
1654
- }
1655
-
1656
- /**
1657
- * Runs search payload.
1658
- * @returns {Record<string, ?>} - Payload searches array when present.
1659
- */
1660
- searchPayload() {
1661
- if (this._searches.length === 0) return {}
1662
-
1663
- return {
1664
- searches: this._searches.map((search) => ({
1665
- column: search.column,
1666
- operator: search.operator,
1667
- path: [...search.path],
1668
- value: search.value
1669
- }))
1670
- }
1671
- }
1672
-
1673
- /**
1674
- * Runs ransack payload.
1675
- * @returns {Record<string, ?>} - Payload ransack hash when present.
1676
- */
1677
- ransackPayload() {
1678
- if (this._ransack.length === 0) return {}
1679
-
1680
- if (this._ransack.length === 1) {
1681
- return {ransack: this._ransack[0]}
1682
- }
1683
-
1684
- return {
1685
- ransack: {
1686
- g: this._ransack,
1687
- m: "and"
1688
- }
1689
- }
1690
- }
1691
-
1692
- /**
1693
- * Runs joins payload.
1694
- * @returns {Record<string, ?>} - Payload joins hash when present.
1695
- */
1696
- joinsPayload() {
1697
- if (Object.keys(this._joins).length === 0) return {}
1698
-
1699
- return {
1700
- joins: normalizeJoins(this._joins)
1701
- }
1702
- }
1703
-
1704
- /**
1705
- * Runs sort payload.
1706
- * @returns {Record<string, ?>} - Payload sort array when present.
1707
- */
1708
- sortPayload() {
1709
- if (this._sort.length === 0) return {}
1710
-
1711
- return {
1712
- sort: this._sort.map((sortEntry) => ({
1713
- column: sortEntry.column,
1714
- direction: sortEntry.direction,
1715
- path: [...sortEntry.path]
1716
- }))
1717
- }
1718
- }
1719
-
1720
- /**
1721
- * Runs group payload.
1722
- * @returns {Record<string, ?>} - Payload group array when present.
1723
- */
1724
- groupPayload() {
1725
- if (this._group.length === 0) return {}
1726
-
1727
- return {
1728
- group: this._group.map((groupEntry) => ({
1729
- column: groupEntry.column,
1730
- path: [...groupEntry.path]
1731
- }))
1732
- }
1733
- }
1734
-
1735
- /**
1736
- * Runs distinct payload.
1737
- * @returns {Record<string, ?>} - Payload distinct flag when enabled.
1738
- */
1739
- distinctPayload() {
1740
- if (!this._distinct) return {}
1741
-
1742
- return {
1743
- distinct: true
1744
- }
1745
- }
1746
-
1747
- /**
1748
- * Runs where payload.
1749
- * @returns {Record<string, ?>} - Payload where hash when present.
1750
- */
1751
- wherePayload() {
1752
- if (Object.keys(this._where).length === 0) return {}
1753
-
1754
- return {
1755
- where: this._where
1305
+ @type {FrontendModelQuery<T>} */ (new FrontendModelQuery({
1306
+ modelClass: this.modelClass,
1307
+ preload: normalizePreload(this._preload)
1308
+ }));
1309
+ newQuery._joins = normalizeJoins(this._joins);
1310
+ newQuery._where = { ...this._where };
1311
+ newQuery._ransack = this._ransack.map((ransackParams) => ({ ...ransackParams }));
1312
+ newQuery._searches = this._searches.map((search) => ({
1313
+ column: search.column,
1314
+ operator: search.operator,
1315
+ path: [...search.path],
1316
+ value: search.value
1317
+ }));
1318
+ newQuery._select = normalizeSelect(this._select);
1319
+ newQuery._selectsExtra = normalizeSelect(this._selectsExtra);
1320
+ newQuery._sort = this._sort.map((sortEntry) => ({
1321
+ column: sortEntry.column,
1322
+ direction: sortEntry.direction,
1323
+ path: [...sortEntry.path]
1324
+ }));
1325
+ newQuery._group = this._group.map((groupEntry) => ({
1326
+ column: groupEntry.column,
1327
+ path: [...groupEntry.path]
1328
+ }));
1329
+ newQuery._distinct = this._distinct;
1330
+ newQuery._limit = this._limit;
1331
+ newQuery._offset = this._offset;
1332
+ newQuery._page = this._page;
1333
+ newQuery._perPage = this._perPage;
1334
+ newQuery._withCount = this._withCount.map((entry) => ({
1335
+ attributeName: entry.attributeName,
1336
+ relationshipName: entry.relationshipName,
1337
+ where: entry.where ? { ...entry.where } : undefined
1338
+ }));
1339
+ newQuery._queryData = this._queryData.map((entry) => (typeof entry === "string" ? entry : { ...entry }));
1340
+ newQuery._abilities = this._abilities.map((entry) => ({
1341
+ actions: [...entry.actions],
1342
+ modelName: entry.modelName
1343
+ }));
1344
+ return newQuery;
1756
1345
  }
1757
- }
1758
-
1759
- /**
1760
- * Runs pagination payload.
1761
- * @returns {Record<string, ?>} - Payload pagination params when present.
1762
- */
1763
- paginationPayload() {
1764
1346
  /**
1765
- * Payload.
1766
- @type {Record<string, ?>} */
1767
- const payload = {}
1768
-
1769
- if (this._limit !== null) payload.limit = this._limit
1770
- if (this._offset !== null) payload.offset = this._offset
1771
- if (this._page !== null) payload.page = this._page
1772
- if (this._perPage !== null) payload.perPage = this._perPage
1773
-
1774
- return payload
1775
- }
1776
-
1777
- /**
1778
- * Runs assert event query supported.
1779
- * @returns {void}
1780
- * @throws {Error} When the query contains list-only options that cannot filter a single lifecycle event.
1781
- */
1782
- assertEventQuerySupported() {
1783
- /**
1784
- * Unsupported options.
1785
- @type {string[]} */
1786
- const unsupportedOptions = []
1787
-
1788
- if (this._sort.length > 0) unsupportedOptions.push("sort")
1789
- if (this._group.length > 0) unsupportedOptions.push("group")
1790
- if (this._distinct) unsupportedOptions.push("distinct")
1791
- if (this._ransack.length > 0) unsupportedOptions.push("ransack")
1792
- if (this._limit !== null || this._offset !== null || this._page !== null || this._perPage !== null) unsupportedOptions.push("pagination")
1793
-
1794
- if (unsupportedOptions.length === 0) return
1795
-
1796
- throw new Error(`Frontend model event queries do not support ${unsupportedOptions.join(", ")}`)
1797
- }
1798
-
1799
- /**
1800
- * Runs event projection payload.
1801
- * @returns {FrontendModelProjectionPayload} - Projection payload used when serializing lifecycle events.
1802
- */
1803
- eventProjectionPayload() {
1804
- this.assertEventQuerySupported()
1805
-
1806
- return {
1807
- ...this.preloadPayload(),
1808
- ...this.selectPayload(),
1809
- ...this.selectsExtraPayload(),
1810
- ...this.withCountPayload(),
1811
- ...this.abilitiesPayload(),
1812
- ...this.queryDataPayload()
1813
- }
1814
- }
1815
-
1816
- /**
1817
- * Runs event filter payload.
1818
- * @returns {FrontendModelEventFilterPayload | null} - Query pieces used to match lifecycle events.
1819
- */
1820
- eventFilterPayload() {
1821
- this.assertEventQuerySupported()
1822
-
1823
- const payload = {
1824
- ...this.joinsPayload(),
1825
- ...this.searchPayload(),
1826
- ...this.wherePayload()
1827
- }
1828
-
1829
- return Object.keys(payload).length === 0 ? null : payload
1830
- }
1831
-
1832
- /**
1833
- * Returns the eventOptionsPayload result.
1834
- * @returns {FrontendModelEventOptionsPayload} - Combined event filter and projection payload.
1835
- */
1836
- eventOptionsPayload() {
1837
- const eventFilterPayload = this.eventFilterPayload()
1838
-
1839
- return {
1840
- eventFilterKey: eventFilterPayload ? frontendModelEventFilterKey(eventFilterPayload) : null,
1841
- eventFilterPayload,
1842
- projectionPayload: this.eventProjectionPayload()
1843
- }
1844
- }
1845
-
1846
- /**
1847
- * Runs load.
1848
- * @returns {Promise<InstanceType<T>[]>} - Loaded model instances.
1849
- */
1850
- async load() {
1851
- const response = await this.modelClass.executeCommand("index", {
1852
- ...this.preloadPayload(),
1853
- ...this.joinsPayload(),
1854
- ...this.ransackPayload(),
1855
- ...this.searchPayload(),
1856
- ...this.selectPayload(),
1857
- ...this.selectsExtraPayload(),
1858
- ...this.groupPayload(),
1859
- ...this.distinctPayload(),
1860
- ...this.sortPayload(),
1861
- ...this.wherePayload(),
1862
- ...this.withCountPayload(),
1863
- ...this.abilitiesPayload(),
1864
- ...this.queryDataPayload(),
1865
- ...this.paginationPayload()
1866
- })
1867
-
1868
- if (!response || typeof response !== "object") {
1869
- throw new Error(`Expected object response but got: ${response}`)
1870
- }
1871
-
1872
- const modelsData = Array.isArray(response.models) ? response.models : []
1873
- /**
1874
- * Models.
1875
- @type {InstanceType<T>[]} */
1876
- const models = modelsData.map((model) => this.modelClass.instantiateFromResponse(model))
1877
-
1878
- // Share a single cohort reference across every sibling so auto-batch-preload
1879
- // can batch lazy relationship access later. Single-record lookups still flow
1880
- // through here (with a cohort of one) and degrade cleanly to per-record load.
1881
- for (const model of models) {
1882
- /**
1883
- * Narrows the runtime value to the documented type.
1884
- @type {?} */ (model)._loadCohort = models
1885
- }
1886
-
1887
- return models
1888
- }
1889
-
1890
- /**
1891
- * Runs to array.
1892
- * @returns {Promise<InstanceType<T>[]>} - Loaded model instances.
1893
- */
1894
- async toArray() {
1895
- return await this.load()
1896
- }
1897
-
1898
- /**
1899
- * Runs count.
1900
- * @returns {Promise<number>} - Number of loaded model instances.
1901
- */
1902
- async count() {
1903
- const response = await this.modelClass.executeCommand("index", {
1904
- ...this.joinsPayload(),
1905
- ...this.ransackPayload(),
1906
- ...this.searchPayload(),
1907
- ...this.groupPayload(),
1908
- ...this.distinctPayload(),
1909
- ...this.wherePayload(),
1910
- ...this.paginationPayload(),
1911
- count: true
1912
- })
1913
-
1914
- if (!response || typeof response !== "object") {
1915
- throw new Error(`Expected object response but got: ${response}`)
1916
- }
1917
-
1918
- if (!Number.isFinite(response.count)) {
1919
- throw new Error(`Expected numeric count response but got: ${response.count}`)
1920
- }
1921
-
1922
- return response.count
1923
- }
1924
-
1925
- /**
1926
- * Runs first.
1927
- * @returns {Promise<InstanceType<T> | null>} - First model matching query.
1928
- */
1929
- async first() {
1930
- const query = this.clone()
1931
-
1932
- if (query._sort.length < 1) {
1933
- query.sort([[this.modelClass.primaryKey(), "asc"]])
1934
- }
1935
-
1936
- query.limit(1)
1937
-
1938
- const models = await query.toArray()
1939
-
1940
- return models[0] || null
1941
- }
1942
-
1943
- /**
1944
- * Runs last.
1945
- * @returns {Promise<InstanceType<T> | null>} - Last model matching query.
1946
- */
1947
- async last() {
1948
- // When pagination is already applied, fetch that scoped window and return its last item.
1949
- if (this._offset !== null || this._page !== null || this._perPage !== null) {
1950
- const models = await this.toArray()
1951
-
1952
- if (models.length < 1) return null
1953
-
1954
- return models[models.length - 1]
1955
- }
1956
-
1957
- const query = this.clone()
1958
-
1959
- if (query._sort.length < 1) {
1960
- query.sort([[this.modelClass.primaryKey(), "desc"]])
1961
- } else {
1962
- query._sort = query._sort.map((sortEntry) => ({
1963
- ...sortEntry,
1964
- direction: reverseSortDirection(sortEntry.direction)
1965
- }))
1966
- }
1967
-
1968
- query.limit(1)
1969
-
1970
- const models = await query.toArray()
1971
-
1972
- return models[0] || null
1973
- }
1974
-
1975
- /**
1976
- * Runs pluck.
1977
- * @param {...(string | string[] | Record<string, ?> | Array<Record<string, ?>>)} columns - Pluck definition(s).
1978
- * @returns {Promise<Array<?>>} - Plucked values.
1979
- */
1980
- async pluck(...columns) {
1981
- if (columns.length < 1) {
1982
- throw new Error("No columns given to pluck")
1983
- }
1984
-
1985
- const normalizedPluck = normalizePluck(columns.length === 1 ? columns[0] : columns)
1986
- const validatedPluck = validatePluckDefinitions({
1987
- modelClass: this.modelClass,
1988
- pluck: normalizedPluck
1989
- })
1990
- const response = await this.modelClass.executeCommand("index", {
1991
- ...this.joinsPayload(),
1992
- ...this.searchPayload(),
1993
- ...this.groupPayload(),
1994
- ...this.distinctPayload(),
1995
- ...this.sortPayload(),
1996
- ...this.wherePayload(),
1997
- ...this.paginationPayload(),
1998
- pluck: validatedPluck
1999
- })
2000
-
2001
- if (!response || typeof response !== "object") {
2002
- throw new Error(`Expected object response but got: ${response}`)
2003
- }
2004
-
2005
- if (!Array.isArray(response.values)) {
2006
- return []
2007
- }
2008
-
2009
- return response.values
2010
- }
2011
-
2012
- /**
2013
- * Runs find.
2014
- * @param {number | string} id - Record id.
2015
- * @returns {Promise<InstanceType<T>>} - Found model.
2016
- */
2017
- async find(id) {
2018
- const pk = this.modelClass.primaryKey()
2019
- const model = await this.findBy({[pk]: id})
2020
-
2021
- if (!model) {
2022
- throw new Error(`${this.modelClass.getModelName()} not found with ${pk}=${id}`)
2023
- }
2024
-
2025
- return model
2026
- }
2027
-
2028
- /**
2029
- * Runs find by.
2030
- * @param {Record<string, ?>} conditions - Conditions.
2031
- * @returns {Promise<InstanceType<T> | null>} - Found model or null.
2032
- */
2033
- async findBy(conditions) {
2034
- const normalizedConditions = this.validatedStructuredConditions(conditions)
2035
- const mergedWhere = {
2036
- ...this._where,
2037
- ...normalizedConditions
2038
- }
2039
-
2040
- const response = await this.modelClass.executeCommand("index", {
2041
- ...this.preloadPayload(),
2042
- ...this.joinsPayload(),
2043
- ...this.searchPayload(),
2044
- ...this.selectPayload(Object.keys(mergedWhere)),
2045
- ...this.selectsExtraPayload(),
2046
- ...this.groupPayload(),
2047
- ...this.distinctPayload(),
2048
- ...this.sortPayload(),
2049
- ...this.abilitiesPayload(),
2050
- ...this.paginationPayload(),
2051
- where: mergedWhere
2052
- })
2053
-
2054
- if (!response || typeof response !== "object") {
2055
- throw new Error(`Expected object response but got: ${response}`)
2056
- }
2057
-
2058
- const models = Array.isArray(response.models) ? response.models : []
2059
-
2060
- for (const modelData of models) {
2061
- const model = this.modelClass.instantiateFromResponse(modelData)
2062
-
2063
- if (this.modelClass.matchesFindByConditions(model, mergedWhere)) {
2064
- return model
2065
- }
2066
- }
2067
-
2068
- return null
2069
- }
2070
-
2071
- /**
2072
- * Runs find by or fail.
2073
- * @param {Record<string, ?>} conditions - Conditions.
2074
- * @returns {Promise<InstanceType<T>>} - Found model.
2075
- */
2076
- async findByOrFail(conditions) {
2077
- const model = await this.findBy(conditions)
2078
-
2079
- if (!model) {
2080
- throw new Error(`${this.modelClass.name} not found for conditions: ${serializeFindConditions(conditions)}`)
2081
- }
2082
-
2083
- return model
2084
- }
2085
-
2086
- /**
2087
- * Runs find or initialize by.
2088
- * @param {Record<string, ?>} conditions - Conditions.
2089
- * @returns {Promise<InstanceType<T>>} - Existing or initialized model.
2090
- */
2091
- async findOrInitializeBy(conditions) {
2092
- const normalizedConditions = this.validatedStructuredConditions(conditions)
2093
- const model = await this.findBy(conditions)
2094
-
2095
- if (model) return model
2096
-
2097
- return /** Narrows the runtime value to the documented type. @type {InstanceType<T>} */ (new this.modelClass(normalizedConditions))
2098
- }
2099
-
2100
- /**
2101
- * Runs find or create by.
2102
- * @param {Record<string, ?>} conditions - Conditions.
2103
- * @param {(model: InstanceType<T>) => Promise<void> | void} [callback] - Optional callback before save.
2104
- * @returns {Promise<InstanceType<T>>} - Existing or newly created model.
2105
- */
2106
- async findOrCreateBy(conditions, callback) {
2107
- const normalizedConditions = this.validatedStructuredConditions(conditions)
2108
- const model = await this.findBy(conditions)
2109
-
2110
- if (model) return model
2111
-
2112
- const newModel = /**
2113
- * Narrows the runtime value to the documented type.
2114
- @type {InstanceType<T>} */ (new this.modelClass(normalizedConditions))
2115
-
2116
- if (callback) {
2117
- await callback(newModel)
2118
- }
2119
-
2120
- await newModel.save()
2121
-
2122
- return newModel
2123
- }
2124
-
2125
- /**
2126
- * Runs validated structured conditions.
2127
- * @param {Record<string, ?>} conditions - Candidate structured conditions.
2128
- * @returns {Record<string, ?>} - Validated conditions.
2129
- */
2130
- validatedStructuredConditions(conditions) {
2131
- this.modelClass.assertFindByConditions(conditions)
2132
-
2133
- return conditions
2134
- }
1347
+ * Runs get model class.
1348
+ * @returns {T} - Root model class.
1349
+ */
1350
+ getModelClass() {
1351
+ return this.modelClass;
1352
+ }
1353
+ /**
1354
+ * Runs preload payload.
1355
+ * @returns {Record<string, ?>} - Payload preload hash when present.
1356
+ */
1357
+ preloadPayload() {
1358
+ if (Object.keys(this._preload).length === 0)
1359
+ return {};
1360
+ return { preload: this._preload };
1361
+ }
1362
+ /**
1363
+ * Runs with count payload.
1364
+ * @returns {Record<string, ?>} - Payload withCount array when present.
1365
+ */
1366
+ withCountPayload() {
1367
+ if (this._withCount.length === 0)
1368
+ return {};
1369
+ return {
1370
+ withCount: this._withCount.map((entry) => ({
1371
+ attributeName: entry.attributeName,
1372
+ relationshipName: entry.relationshipName,
1373
+ where: entry.where || undefined
1374
+ }))
1375
+ };
1376
+ }
1377
+ /**
1378
+ * Runs abilities payload.
1379
+ * @returns {Record<string, ?>} - Payload abilities array when present.
1380
+ */
1381
+ abilitiesPayload() {
1382
+ if (this._abilities.length === 0)
1383
+ return {};
1384
+ return {
1385
+ abilities: this._abilities.map((entry) => ({
1386
+ actions: [...entry.actions],
1387
+ modelName: entry.modelName
1388
+ }))
1389
+ };
1390
+ }
1391
+ /**
1392
+ * Runs query data payload.
1393
+ * @returns {Record<string, ?>} - Payload queryData spec when present.
1394
+ */
1395
+ queryDataPayload() {
1396
+ if (this._queryData.length === 0)
1397
+ return {};
1398
+ // Single accumulated spec goes on the wire verbatim. The backend
1399
+ // normalizer accepts string/array/object at each level, so we can
1400
+ // ship multiple `.queryData(...)` calls as an array.
1401
+ return {
1402
+ queryData: this._queryData.length === 1 ? this._queryData[0] : this._queryData
1403
+ };
1404
+ }
1405
+ /**
1406
+ * Runs select payload.
1407
+ * @param {string[]} [requiredAttributes] - Extra required attributes for root model selection.
1408
+ * @returns {Record<string, ?>} - Payload select hash when present.
1409
+ */
1410
+ selectPayload(requiredAttributes = []) {
1411
+ const select = this.selectWithRequiredRootAttributes(requiredAttributes);
1412
+ if (Object.keys(select).length === 0)
1413
+ return {};
1414
+ return { select };
1415
+ }
1416
+ /**
1417
+ * Runs selects extra payload.
1418
+ * @returns {Record<string, ?>} - Payload selectsExtra hash when present.
1419
+ */
1420
+ selectsExtraPayload() {
1421
+ if (Object.keys(this._selectsExtra).length === 0)
1422
+ return {};
1423
+ return { selectsExtra: this._selectsExtra };
1424
+ }
1425
+ /**
1426
+ * Runs search payload.
1427
+ * @returns {Record<string, ?>} - Payload searches array when present.
1428
+ */
1429
+ searchPayload() {
1430
+ if (this._searches.length === 0)
1431
+ return {};
1432
+ return {
1433
+ searches: this._searches.map((search) => ({
1434
+ column: search.column,
1435
+ operator: search.operator,
1436
+ path: [...search.path],
1437
+ value: search.value
1438
+ }))
1439
+ };
1440
+ }
1441
+ /**
1442
+ * Runs ransack payload.
1443
+ * @returns {Record<string, ?>} - Payload ransack hash when present.
1444
+ */
1445
+ ransackPayload() {
1446
+ if (this._ransack.length === 0)
1447
+ return {};
1448
+ if (this._ransack.length === 1) {
1449
+ return { ransack: this._ransack[0] };
1450
+ }
1451
+ return {
1452
+ ransack: {
1453
+ g: this._ransack,
1454
+ m: "and"
1455
+ }
1456
+ };
1457
+ }
1458
+ /**
1459
+ * Runs joins payload.
1460
+ * @returns {Record<string, ?>} - Payload joins hash when present.
1461
+ */
1462
+ joinsPayload() {
1463
+ if (Object.keys(this._joins).length === 0)
1464
+ return {};
1465
+ return {
1466
+ joins: normalizeJoins(this._joins)
1467
+ };
1468
+ }
1469
+ /**
1470
+ * Runs sort payload.
1471
+ * @returns {Record<string, ?>} - Payload sort array when present.
1472
+ */
1473
+ sortPayload() {
1474
+ if (this._sort.length === 0)
1475
+ return {};
1476
+ return {
1477
+ sort: this._sort.map((sortEntry) => ({
1478
+ column: sortEntry.column,
1479
+ direction: sortEntry.direction,
1480
+ path: [...sortEntry.path]
1481
+ }))
1482
+ };
1483
+ }
1484
+ /**
1485
+ * Runs group payload.
1486
+ * @returns {Record<string, ?>} - Payload group array when present.
1487
+ */
1488
+ groupPayload() {
1489
+ if (this._group.length === 0)
1490
+ return {};
1491
+ return {
1492
+ group: this._group.map((groupEntry) => ({
1493
+ column: groupEntry.column,
1494
+ path: [...groupEntry.path]
1495
+ }))
1496
+ };
1497
+ }
1498
+ /**
1499
+ * Runs distinct payload.
1500
+ * @returns {Record<string, ?>} - Payload distinct flag when enabled.
1501
+ */
1502
+ distinctPayload() {
1503
+ if (!this._distinct)
1504
+ return {};
1505
+ return {
1506
+ distinct: true
1507
+ };
1508
+ }
1509
+ /**
1510
+ * Runs where payload.
1511
+ * @returns {Record<string, ?>} - Payload where hash when present.
1512
+ */
1513
+ wherePayload() {
1514
+ if (Object.keys(this._where).length === 0)
1515
+ return {};
1516
+ return {
1517
+ where: this._where
1518
+ };
1519
+ }
1520
+ /**
1521
+ * Runs pagination payload.
1522
+ * @returns {Record<string, ?>} - Payload pagination params when present.
1523
+ */
1524
+ paginationPayload() {
1525
+ /**
1526
+ * Payload.
1527
+ @type {Record<string, ?>} */
1528
+ const payload = {};
1529
+ if (this._limit !== null)
1530
+ payload.limit = this._limit;
1531
+ if (this._offset !== null)
1532
+ payload.offset = this._offset;
1533
+ if (this._page !== null)
1534
+ payload.page = this._page;
1535
+ if (this._perPage !== null)
1536
+ payload.perPage = this._perPage;
1537
+ return payload;
1538
+ }
1539
+ /**
1540
+ * Runs assert event query supported.
1541
+ * @returns {void}
1542
+ * @throws {Error} When the query contains list-only options that cannot filter a single lifecycle event.
1543
+ */
1544
+ assertEventQuerySupported() {
1545
+ /**
1546
+ * Unsupported options.
1547
+ @type {string[]} */
1548
+ const unsupportedOptions = [];
1549
+ if (this._sort.length > 0)
1550
+ unsupportedOptions.push("sort");
1551
+ if (this._group.length > 0)
1552
+ unsupportedOptions.push("group");
1553
+ if (this._distinct)
1554
+ unsupportedOptions.push("distinct");
1555
+ if (this._ransack.length > 0)
1556
+ unsupportedOptions.push("ransack");
1557
+ if (this._limit !== null || this._offset !== null || this._page !== null || this._perPage !== null)
1558
+ unsupportedOptions.push("pagination");
1559
+ if (unsupportedOptions.length === 0)
1560
+ return;
1561
+ throw new Error(`Frontend model event queries do not support ${unsupportedOptions.join(", ")}`);
1562
+ }
1563
+ /**
1564
+ * Runs event projection payload.
1565
+ * @returns {FrontendModelProjectionPayload} - Projection payload used when serializing lifecycle events.
1566
+ */
1567
+ eventProjectionPayload() {
1568
+ this.assertEventQuerySupported();
1569
+ return {
1570
+ ...this.preloadPayload(),
1571
+ ...this.selectPayload(),
1572
+ ...this.selectsExtraPayload(),
1573
+ ...this.withCountPayload(),
1574
+ ...this.abilitiesPayload(),
1575
+ ...this.queryDataPayload()
1576
+ };
1577
+ }
1578
+ /**
1579
+ * Runs event filter payload.
1580
+ * @returns {FrontendModelEventFilterPayload | null} - Query pieces used to match lifecycle events.
1581
+ */
1582
+ eventFilterPayload() {
1583
+ this.assertEventQuerySupported();
1584
+ const payload = {
1585
+ ...this.joinsPayload(),
1586
+ ...this.searchPayload(),
1587
+ ...this.wherePayload()
1588
+ };
1589
+ return Object.keys(payload).length === 0 ? null : payload;
1590
+ }
1591
+ /**
1592
+ * Returns the eventOptionsPayload result.
1593
+ * @returns {FrontendModelEventOptionsPayload} - Combined event filter and projection payload.
1594
+ */
1595
+ eventOptionsPayload() {
1596
+ const eventFilterPayload = this.eventFilterPayload();
1597
+ return {
1598
+ eventFilterKey: eventFilterPayload ? frontendModelEventFilterKey(eventFilterPayload) : null,
1599
+ eventFilterPayload,
1600
+ projectionPayload: this.eventProjectionPayload()
1601
+ };
1602
+ }
1603
+ /**
1604
+ * Runs load.
1605
+ * @returns {Promise<InstanceType<T>[]>} - Loaded model instances.
1606
+ */
1607
+ async load() {
1608
+ const response = await this.modelClass.executeCommand("index", {
1609
+ ...this.preloadPayload(),
1610
+ ...this.joinsPayload(),
1611
+ ...this.ransackPayload(),
1612
+ ...this.searchPayload(),
1613
+ ...this.selectPayload(),
1614
+ ...this.selectsExtraPayload(),
1615
+ ...this.groupPayload(),
1616
+ ...this.distinctPayload(),
1617
+ ...this.sortPayload(),
1618
+ ...this.wherePayload(),
1619
+ ...this.withCountPayload(),
1620
+ ...this.abilitiesPayload(),
1621
+ ...this.queryDataPayload(),
1622
+ ...this.paginationPayload()
1623
+ });
1624
+ if (!response || typeof response !== "object") {
1625
+ throw new Error(`Expected object response but got: ${response}`);
1626
+ }
1627
+ const modelsData = Array.isArray(response.models) ? response.models : [];
1628
+ /**
1629
+ * Models.
1630
+ @type {InstanceType<T>[]} */
1631
+ const models = modelsData.map((model) => this.modelClass.instantiateFromResponse(model));
1632
+ // Share a single cohort reference across every sibling so auto-batch-preload
1633
+ // can batch lazy relationship access later. Single-record lookups still flow
1634
+ // through here (with a cohort of one) and degrade cleanly to per-record load.
1635
+ for (const model of models) {
1636
+ /**
1637
+ * Narrows the runtime value to the documented type.
1638
+ @type {?} */ (model)._loadCohort = models;
1639
+ }
1640
+ return models;
1641
+ }
1642
+ /**
1643
+ * Runs to array.
1644
+ * @returns {Promise<InstanceType<T>[]>} - Loaded model instances.
1645
+ */
1646
+ async toArray() {
1647
+ return await this.load();
1648
+ }
1649
+ /**
1650
+ * Runs count.
1651
+ * @returns {Promise<number>} - Number of loaded model instances.
1652
+ */
1653
+ async count() {
1654
+ const response = await this.modelClass.executeCommand("index", {
1655
+ ...this.joinsPayload(),
1656
+ ...this.ransackPayload(),
1657
+ ...this.searchPayload(),
1658
+ ...this.groupPayload(),
1659
+ ...this.distinctPayload(),
1660
+ ...this.wherePayload(),
1661
+ ...this.paginationPayload(),
1662
+ count: true
1663
+ });
1664
+ if (!response || typeof response !== "object") {
1665
+ throw new Error(`Expected object response but got: ${response}`);
1666
+ }
1667
+ if (!Number.isFinite(response.count)) {
1668
+ throw new Error(`Expected numeric count response but got: ${response.count}`);
1669
+ }
1670
+ return response.count;
1671
+ }
1672
+ /**
1673
+ * Runs first.
1674
+ * @returns {Promise<InstanceType<T> | null>} - First model matching query.
1675
+ */
1676
+ async first() {
1677
+ const query = this.clone();
1678
+ if (query._sort.length < 1) {
1679
+ query.sort([[this.modelClass.primaryKey(), "asc"]]);
1680
+ }
1681
+ query.limit(1);
1682
+ const models = await query.toArray();
1683
+ return models[0] || null;
1684
+ }
1685
+ /**
1686
+ * Runs last.
1687
+ * @returns {Promise<InstanceType<T> | null>} - Last model matching query.
1688
+ */
1689
+ async last() {
1690
+ // When pagination is already applied, fetch that scoped window and return its last item.
1691
+ if (this._offset !== null || this._page !== null || this._perPage !== null) {
1692
+ const models = await this.toArray();
1693
+ if (models.length < 1)
1694
+ return null;
1695
+ return models[models.length - 1];
1696
+ }
1697
+ const query = this.clone();
1698
+ if (query._sort.length < 1) {
1699
+ query.sort([[this.modelClass.primaryKey(), "desc"]]);
1700
+ }
1701
+ else {
1702
+ query._sort = query._sort.map((sortEntry) => ({
1703
+ ...sortEntry,
1704
+ direction: reverseSortDirection(sortEntry.direction)
1705
+ }));
1706
+ }
1707
+ query.limit(1);
1708
+ const models = await query.toArray();
1709
+ return models[0] || null;
1710
+ }
1711
+ /**
1712
+ * Runs pluck.
1713
+ * @param {...(string | string[] | Record<string, ?> | Array<Record<string, ?>>)} columns - Pluck definition(s).
1714
+ * @returns {Promise<Array<?>>} - Plucked values.
1715
+ */
1716
+ async pluck(...columns) {
1717
+ if (columns.length < 1) {
1718
+ throw new Error("No columns given to pluck");
1719
+ }
1720
+ const normalizedPluck = normalizePluck(columns.length === 1 ? columns[0] : columns);
1721
+ const validatedPluck = validatePluckDefinitions({
1722
+ modelClass: this.modelClass,
1723
+ pluck: normalizedPluck
1724
+ });
1725
+ const response = await this.modelClass.executeCommand("index", {
1726
+ ...this.joinsPayload(),
1727
+ ...this.searchPayload(),
1728
+ ...this.groupPayload(),
1729
+ ...this.distinctPayload(),
1730
+ ...this.sortPayload(),
1731
+ ...this.wherePayload(),
1732
+ ...this.paginationPayload(),
1733
+ pluck: validatedPluck
1734
+ });
1735
+ if (!response || typeof response !== "object") {
1736
+ throw new Error(`Expected object response but got: ${response}`);
1737
+ }
1738
+ if (!Array.isArray(response.values)) {
1739
+ return [];
1740
+ }
1741
+ return response.values;
1742
+ }
1743
+ /**
1744
+ * Runs find.
1745
+ * @param {number | string} id - Record id.
1746
+ * @returns {Promise<InstanceType<T>>} - Found model.
1747
+ */
1748
+ async find(id) {
1749
+ const pk = this.modelClass.primaryKey();
1750
+ const model = await this.findBy({ [pk]: id });
1751
+ if (!model) {
1752
+ throw new Error(`${this.modelClass.getModelName()} not found with ${pk}=${id}`);
1753
+ }
1754
+ return model;
1755
+ }
1756
+ /**
1757
+ * Runs find by.
1758
+ * @param {Record<string, ?>} conditions - Conditions.
1759
+ * @returns {Promise<InstanceType<T> | null>} - Found model or null.
1760
+ */
1761
+ async findBy(conditions) {
1762
+ const normalizedConditions = this.validatedStructuredConditions(conditions);
1763
+ const mergedWhere = {
1764
+ ...this._where,
1765
+ ...normalizedConditions
1766
+ };
1767
+ const response = await this.modelClass.executeCommand("index", {
1768
+ ...this.preloadPayload(),
1769
+ ...this.joinsPayload(),
1770
+ ...this.searchPayload(),
1771
+ ...this.selectPayload(Object.keys(mergedWhere)),
1772
+ ...this.selectsExtraPayload(),
1773
+ ...this.groupPayload(),
1774
+ ...this.distinctPayload(),
1775
+ ...this.sortPayload(),
1776
+ ...this.abilitiesPayload(),
1777
+ ...this.paginationPayload(),
1778
+ where: mergedWhere
1779
+ });
1780
+ if (!response || typeof response !== "object") {
1781
+ throw new Error(`Expected object response but got: ${response}`);
1782
+ }
1783
+ const models = Array.isArray(response.models) ? response.models : [];
1784
+ for (const modelData of models) {
1785
+ const model = this.modelClass.instantiateFromResponse(modelData);
1786
+ if (this.modelClass.matchesFindByConditions(model, mergedWhere)) {
1787
+ return model;
1788
+ }
1789
+ }
1790
+ return null;
1791
+ }
1792
+ /**
1793
+ * Runs find by or fail.
1794
+ * @param {Record<string, ?>} conditions - Conditions.
1795
+ * @returns {Promise<InstanceType<T>>} - Found model.
1796
+ */
1797
+ async findByOrFail(conditions) {
1798
+ const model = await this.findBy(conditions);
1799
+ if (!model) {
1800
+ throw new Error(`${this.modelClass.name} not found for conditions: ${serializeFindConditions(conditions)}`);
1801
+ }
1802
+ return model;
1803
+ }
1804
+ /**
1805
+ * Runs find or initialize by.
1806
+ * @param {Record<string, ?>} conditions - Conditions.
1807
+ * @returns {Promise<InstanceType<T>>} - Existing or initialized model.
1808
+ */
1809
+ async findOrInitializeBy(conditions) {
1810
+ const normalizedConditions = this.validatedStructuredConditions(conditions);
1811
+ const model = await this.findBy(conditions);
1812
+ if (model)
1813
+ return model;
1814
+ return /** Narrows the runtime value to the documented type. @type {InstanceType<T>} */ (new this.modelClass(normalizedConditions));
1815
+ }
1816
+ /**
1817
+ * Runs find or create by.
1818
+ * @param {Record<string, ?>} conditions - Conditions.
1819
+ * @param {(model: InstanceType<T>) => Promise<void> | void} [callback] - Optional callback before save.
1820
+ * @returns {Promise<InstanceType<T>>} - Existing or newly created model.
1821
+ */
1822
+ async findOrCreateBy(conditions, callback) {
1823
+ const normalizedConditions = this.validatedStructuredConditions(conditions);
1824
+ const model = await this.findBy(conditions);
1825
+ if (model)
1826
+ return model;
1827
+ const newModel = /**
1828
+ * Narrows the runtime value to the documented type.
1829
+ @type {InstanceType<T>} */ (new this.modelClass(normalizedConditions));
1830
+ if (callback) {
1831
+ await callback(newModel);
1832
+ }
1833
+ await newModel.save();
1834
+ return newModel;
1835
+ }
1836
+ /**
1837
+ * Runs validated structured conditions.
1838
+ * @param {Record<string, ?>} conditions - Candidate structured conditions.
1839
+ * @returns {Record<string, ?>} - Validated conditions.
1840
+ */
1841
+ validatedStructuredConditions(conditions) {
1842
+ this.modelClass.assertFindByConditions(conditions);
1843
+ return conditions;
1844
+ }
2135
1845
  }
2136
-
2137
1846
  /**
2138
1847
  * Runs frontend model event filter key.
2139
1848
  * @param {FrontendModelEventFilterPayload} payload - Event filter payload.
2140
1849
  * @returns {string} - Stable key for event filter matching.
2141
1850
  */
2142
1851
  function frontendModelEventFilterKey(payload) {
2143
- return JSON.stringify(payload)
1852
+ return JSON.stringify(payload);
2144
1853
  }
2145
-
2146
1854
  /**
2147
1855
  * Runs apply frontend model projection options.
2148
1856
  * @param {FrontendModelQuery<typeof import("./base.js").default>} query - Query receiving projection options.
@@ -2150,14 +1858,19 @@ function frontendModelEventFilterKey(payload) {
2150
1858
  * @returns {void}
2151
1859
  */
2152
1860
  function applyFrontendModelProjectionOptions(query, options) {
2153
- if (options.select !== undefined) query.select(options.select)
2154
- if (options.selectsExtra !== undefined) query.selectsExtra(options.selectsExtra)
2155
- if (options.preload !== undefined) query.preload(options.preload)
2156
- if (options.withCount !== undefined) query.withCount(options.withCount)
2157
- if (options.abilities !== undefined) query.abilities(options.abilities)
2158
- if (options.queryData !== undefined) query.queryData(options.queryData)
1861
+ if (options.select !== undefined)
1862
+ query.select(options.select);
1863
+ if (options.selectsExtra !== undefined)
1864
+ query.selectsExtra(options.selectsExtra);
1865
+ if (options.preload !== undefined)
1866
+ query.preload(options.preload);
1867
+ if (options.withCount !== undefined)
1868
+ query.withCount(options.withCount);
1869
+ if (options.abilities !== undefined)
1870
+ query.abilities(options.abilities);
1871
+ if (options.queryData !== undefined)
1872
+ query.queryData(options.queryData);
2159
1873
  }
2160
-
2161
1874
  /**
2162
1875
  * Runs assert frontend model event query class.
2163
1876
  * @param {typeof import("./base.js").default} modelClass - Expected frontend model class.
@@ -2165,22 +1878,20 @@ function applyFrontendModelProjectionOptions(query, options) {
2165
1878
  * @returns {void}
2166
1879
  */
2167
1880
  function assertFrontendModelEventQueryClass(modelClass, query) {
2168
- if (query.modelClass === modelClass) return
2169
-
2170
- throw new Error(`Cannot subscribe ${modelClass.name} events with a ${query.modelClass.name} query`)
1881
+ if (query.modelClass === modelClass)
1882
+ return;
1883
+ throw new Error(`Cannot subscribe ${modelClass.name} events with a ${query.modelClass.name} query`);
2171
1884
  }
2172
-
2173
1885
  /**
2174
1886
  * Runs assert frontend model event options object.
2175
1887
  * @param {FrontendModelEventOptions} options - Candidate event options.
2176
1888
  * @returns {void}
2177
1889
  */
2178
1890
  function assertFrontendModelEventOptionsObject(options) {
2179
- if (options && typeof options === "object" && !Array.isArray(options)) return
2180
-
2181
- throw new Error(`Frontend model event options must be a query or an options object, got: ${options}`)
1891
+ if (options && typeof options === "object" && !Array.isArray(options))
1892
+ return;
1893
+ throw new Error(`Frontend model event options must be a query or an options object, got: ${options}`);
2182
1894
  }
2183
-
2184
1895
  /**
2185
1896
  * Runs cloned frontend model event query.
2186
1897
  * @param {typeof import("./base.js").default} modelClass - Frontend model class.
@@ -2188,11 +1899,9 @@ function assertFrontendModelEventOptionsObject(options) {
2188
1899
  * @returns {FrontendModelQuery<typeof import("./base.js").default>} - Cloned query used by event subscriptions.
2189
1900
  */
2190
1901
  function clonedFrontendModelEventQuery(modelClass, query) {
2191
- assertFrontendModelEventQueryClass(modelClass, query)
2192
-
2193
- return query.clone()
1902
+ assertFrontendModelEventQueryClass(modelClass, query);
1903
+ return query.clone();
2194
1904
  }
2195
-
2196
1905
  /**
2197
1906
  * Runs frontend model event query from options object.
2198
1907
  * @param {typeof import("./base.js").default} modelClass - Frontend model class.
@@ -2200,19 +1909,15 @@ function clonedFrontendModelEventQuery(modelClass, query) {
2200
1909
  * @returns {FrontendModelQuery<typeof import("./base.js").default>} - Query used by event subscriptions.
2201
1910
  */
2202
1911
  function frontendModelEventQueryFromOptionsObject(modelClass, options) {
2203
- if (options.query !== undefined && !(options.query instanceof FrontendModelQuery)) {
2204
- throw new Error("Frontend model event option query must be a FrontendModelQuery")
2205
- }
2206
-
2207
- const query = options.query
2208
- ? options.query.clone()
2209
- : new FrontendModelQuery({modelClass})
2210
-
2211
- assertFrontendModelEventQueryClass(modelClass, query)
2212
-
2213
- return query
1912
+ if (options.query !== undefined && !(options.query instanceof FrontendModelQuery)) {
1913
+ throw new Error("Frontend model event option query must be a FrontendModelQuery");
1914
+ }
1915
+ const query = options.query
1916
+ ? options.query.clone()
1917
+ : new FrontendModelQuery({ modelClass });
1918
+ assertFrontendModelEventQueryClass(modelClass, query);
1919
+ return query;
2214
1920
  }
2215
-
2216
1921
  /**
2217
1922
  * Runs frontend model event query.
2218
1923
  * @param {typeof import("./base.js").default} modelClass - Frontend model class.
@@ -2220,20 +1925,16 @@ function frontendModelEventQueryFromOptionsObject(modelClass, options) {
2220
1925
  * @returns {FrontendModelQuery<typeof import("./base.js").default>} - Normalized query used by event subscriptions.
2221
1926
  */
2222
1927
  function frontendModelEventQuery(modelClass, options = {}) {
2223
- if (options instanceof FrontendModelQuery) return clonedFrontendModelEventQuery(modelClass, options)
2224
-
2225
- assertFrontendModelEventOptionsObject(options)
2226
-
2227
- const optionsObject = /**
2228
- * Narrows the runtime value to the documented type.
2229
- @type {FrontendModelEventOptionsObject} */ (options)
2230
- const query = frontendModelEventQueryFromOptionsObject(modelClass, optionsObject)
2231
-
2232
- applyFrontendModelProjectionOptions(query, optionsObject)
2233
-
2234
- return query
1928
+ if (options instanceof FrontendModelQuery)
1929
+ return clonedFrontendModelEventQuery(modelClass, options);
1930
+ assertFrontendModelEventOptionsObject(options);
1931
+ const optionsObject = /**
1932
+ * Narrows the runtime value to the documented type.
1933
+ @type {FrontendModelEventOptionsObject} */ (options);
1934
+ const query = frontendModelEventQueryFromOptionsObject(modelClass, optionsObject);
1935
+ applyFrontendModelProjectionOptions(query, optionsObject);
1936
+ return query;
2235
1937
  }
2236
-
2237
1938
  /**
2238
1939
  * Runs the frontendModelEventOptionsPayload helper.
2239
1940
  * @param {typeof import("./base.js").default} modelClass - Frontend model class.
@@ -2241,5 +1942,6 @@ function frontendModelEventQuery(modelClass, options = {}) {
2241
1942
  * @returns {FrontendModelEventOptionsPayload} - Normalized event subscription payload.
2242
1943
  */
2243
1944
  export function frontendModelEventOptionsPayload(modelClass, options = {}) {
2244
- return frontendModelEventQuery(modelClass, options).eventOptionsPayload()
1945
+ return frontendModelEventQuery(modelClass, options).eventOptionsPayload();
2245
1946
  }
1947
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicXVlcnkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvZnJvbnRlbmQtbW9kZWxzL3F1ZXJ5LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLFlBQVk7QUFFWixPQUFPLEVBQUMseUJBQXlCLEVBQUMsTUFBTSxxQkFBcUIsQ0FBQTtBQUM3RCxPQUFPLEVBQUMscUJBQXFCLEVBQUUsZ0JBQWdCLEVBQUMsTUFBTSxxQkFBcUIsQ0FBQTtBQUMzRSxPQUFPLEVBQUMsc0JBQXNCLEVBQUMsTUFBTSx5QkFBeUIsQ0FBQTtBQUM5RCxPQUFPLGFBQWEsTUFBTSwwQkFBMEIsQ0FBQTtBQUVwRDs7Ozs7OztHQU9HO0FBQ0g7OztHQUdHO0FBQ0g7OztHQUdHO0FBQ0g7OztHQUdHO0FBQ0g7Ozs7Ozs7OztHQVNHO0FBQ0g7OztHQUdHO0FBQ0g7OztHQUdHO0FBQ0g7Ozs7Ozs7OztHQVNHO0FBQ0g7Ozs7OztHQU1HO0FBQ0g7OztHQUdHO0FBQ0g7Ozs7OztHQU1HO0FBRUg7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSxnQkFBZ0IsQ0FBQyxPQUFPO0lBQ3RDLElBQUksQ0FBQyxPQUFPO1FBQUUsT0FBTyxFQUFFLENBQUE7SUFFdkIsSUFBSSxPQUFPLEtBQUssSUFBSTtRQUFFLE9BQU8sRUFBRSxDQUFBO0lBRS9CLElBQUksT0FBTyxPQUFPLEtBQUssUUFBUSxFQUFFLENBQUM7UUFDaEMsT0FBTyxFQUFDLENBQUMsT0FBTyxDQUFDLEVBQUUsSUFBSSxFQUFDLENBQUE7SUFDMUIsQ0FBQztJQUVELElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1FBQzNCOzs2RUFFcUU7UUFDckUsTUFBTSxVQUFVLEdBQUcsRUFBRSxDQUFBO1FBRXJCLEtBQUssTUFBTSxLQUFLLElBQUksT0FBTyxFQUFFLENBQUM7WUFDNUIsSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLEVBQUUsQ0FBQztnQkFDOUIsVUFBVSxDQUFDLEtBQUss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SztRQUNULElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsY0FBYyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUE7UUFFMUMsT0FBTyxJQUFJLENBQUE7SUFDYixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILFFBQVEsQ0FBQyxLQUFLLEdBQUcsSUFBSTtRQUNuQixJQUFJLE9BQU8sS0FBSyxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQy9CLE1BQU0sSUFBSSxLQUFLLENBQUMsb0NBQW9DLE9BQU8sS0FBSyxFQUFFLENBQUMsQ0FBQTtRQUNyRSxDQUFDO1FBRUQsSUFBSSxDQUFDLFNBQVMsR0FBRyxLQUFLLENBQUE7UUFFdEIsT0FBTyxJQUFJLENBQUE7SUFDYixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILEtBQUssQ0FBQyxLQUFLO1FBQ1QsSUFBSSxDQUFDLE1BQU0sR0FBRyx3QkFBd0IsQ0FBQyxLQUFLLEVBQUUsT0FBTyxFQUFFLEVBQUMsR0FBRyxFQUFFLENBQUMsRUFBQyxDQUFDLENBQUE7UUFDaEUsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUE7UUFFakIsT0FBTyxJQUFJLENBQUE7SUFDYixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILE1BQU0sQ0FBQyxLQUFLO1FBQ1YsSUFBSSxDQUFDLE9BQU8sR0FBRyx3QkFBd0IsQ0FBQyxLQUFLLEVBQUUsUUFBUSxFQUFFLEVBQUMsR0FBRyxFQUFFLENBQUMsRUFBQyxDQUFDLENBQUE7UUFDbEUsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUE7UUFFakIsT0FBTyxJQUFJLENBQUE7SUFDYixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILElBQUksQ0FBQyxVQUFVO1FBQ2IsSUFBSSxDQUFDLEtBQUssR0FBRyx3QkFBd0IsQ0FBQyxVQUFVLEVBQUUsTUFBTSxFQUFFLEVBQUMsR0FBRyxFQUFFLENBQUMsRUFBQyxDQUFDLENBQUE7UUFDbkUsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLFFBQVEsSUFBSSxFQUFFLENBQUE7UUFFcEMsSUFBSSxDQUFDLE1B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Q0FBQTtJQUVwRyxxQ0FBcUMsQ0FBQyxPQUFPLENBQUMsQ0FBQTtJQUU5QyxNQUFNLGFBQWEsR0FBRzs7c0VBRTRDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQTtJQUM1RSxNQUFNLEtBQUssR0FBRyx3Q0FBd0MsQ0FBQyxVQUFVLEVBQUUsYUFBYSxDQUFDLENBQUE7SUFFakYsbUNBQW1DLENBQUMsS0FBSyxFQUFFLGFBQWEsQ0FBQyxDQUFBO0lBRXpELE9BQU8sS0FBSyxDQUFBO0FBQ2QsQ0FBQztBQUVEOzs7OztHQUtHO0FBQ0gsTUFBTSxVQUFVLGdDQUFnQyxDQUFDLFVBQVUsRUFBRSxPQUFPLEdBQUcsRUFBRTtJQUN2RSxPQUFPLHVCQUF1QixDQUFDLFVBQVUsRUFBRSxPQUFPLENBQUMsQ0FBQyxtQkFBbUIsRUFBRSxDQUFBO0FBQzNFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBAdHMtY2hlY2tcblxuaW1wb3J0IHtyZXNvbHZlRnJvbnRlbmRNb2RlbENsYXNzfSBmcm9tIFwiLi9tb2RlbC1yZWdpc3RyeS5qc1wiXG5pbXBvcnQge25vcm1hbGl6ZVJhbnNhY2tHcm91cCwgcGFyc2VSYW5zYWNrU29ydH0gZnJvbSBcIi4uL3V0aWxzL3JhbnNhY2suanNcIlxuaW1wb3J0IHtpc01vZGVsU2NvcGVEZXNjcmlwdG9yfSBmcm9tIFwiLi4vdXRpbHMvbW9kZWwtc2NvcGUuanNcIlxuaW1wb3J0IGlzUGxhaW5PYmplY3QgZnJvbSBcIi4uL3V0aWxzL3BsYWluLW9iamVjdC5qc1wiXG5cbi8qKlxuICogRnJvbnRlbmRNb2RlbFNlYXJjaCB0eXBlLlxuICogQHR5cGVkZWYge29iamVjdH0gRnJvbnRlbmRNb2RlbFNlYXJjaFxuICogQHByb3BlcnR5IHtzdHJpbmd9IGNvbHVtbiAtIEF0dHJpYnV0ZSBuYW1lIHRvIHNlYXJjaC5cbiAqIEBwcm9wZXJ0eSB7XCJlcVwiIHwgXCJsaWtlXCIgfCBcIm5vdEVxXCIgfCBcImd0XCIgfCBcImd0ZXFcIiB8IFwibHRcIiB8IFwibHRlcVwifSBvcGVyYXRvciAtIFNlYXJjaCBvcGVyYXRvci5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nW119IHBhdGggLSBSZWxhdGlvbnNoaXAgcGF0aCBmcm9tIHJvb3QgbW9kZWwuXG4gKiBAcHJvcGVydHkgez99IHZhbHVlIC0gU2VhcmNoIHZhbHVlLlxuICovXG4vKipcbiAqIEZyb250ZW5kTW9kZWxUcmFuc3BvcnRWYWx1ZSB0eXBlLlxuICogQHR5cGVkZWYge251bGwgfCBib29sZWFuIHwgbnVtYmVyIHwgc3RyaW5nIHwgb2JqZWN0fSBGcm9udGVuZE1vZGVsVHJhbnNwb3J0VmFsdWVcbiAqL1xuLyoqXG4gKiBEZWZpbmVzIHRoaXMgdHlwZWRlZi5cbiAqIEB0eXBlZGVmIHt7YXR0cmlidXRlTmFtZTogc3RyaW5nLCByZWxhdGlvbnNoaXBOYW1lOiBzdHJpbmcsIHdoZXJlPzogUmVjb3JkPHN0cmluZywgRnJvbnRlbmRNb2RlbFRyYW5zcG9ydFZhbHVlPn19IEZyb250ZW5kTW9kZWxXaXRoQ291bnRQYXlsb2FkRW50cnlcbiAqL1xuLyoqXG4gKiBEZWZpbmVzIHRoaXMgdHlwZWRlZi5cbiAqIEB0eXBlZGVmIHt7bW9kZWxOYW1lOiBzdHJpbmcsIGFjdGlvbnM6IHN0cmluZ1tdfX0gRnJvbnRlbmRNb2RlbEFiaWxpdGllc1BheWxvYWRFbnRyeVxuICovXG4vKipcbiAqIEZyb250ZW5kTW9kZWxQcm9qZWN0aW9uT3B0aW9ucyB0eXBlLlxuICogQHR5cGVkZWYge29iamVjdH0gRnJvbnRlbmRNb2RlbFByb2plY3Rpb25PcHRpb25zXG4gKiBAcHJvcGVydHkge1JlY29yZDxzdHJpbmcsIHN0cmluZ1tdIHwgc3RyaW5nPiB8IHN0cmluZyB8IHN0cmluZ1tdfSBbc2VsZWN0XSAtIE1vZGVsLWF3YXJlIGF0dHJpYnV0ZSBzZWxlY3QgbWFwIG9yIHJvb3QtbW9kZWwgc2hvcnRoYW5kLlxuICogQHByb3BlcnR5IHtSZWNvcmQ8c3RyaW5nLCBzdHJpbmdbXSB8IHN0cmluZz4gfCBzdHJpbmcgfCBzdHJpbmdbXX0gW3NlbGVjdHNFeHRyYV0gLSBFeHRyYSBhdHRyaWJ1dGVzIHRvIGxvYWQgaW4gYWRkaXRpb24gdG8gdGhlIGRlZmF1bHRzLCBrZXllZCBieSBtb2RlbCBuYW1lIG9yIHJvb3QtbW9kZWwgc2hvcnRoYW5kLlxuICogQHByb3BlcnR5IHtpbXBvcnQoXCIuLi9kYXRhYmFzZS9xdWVyeS9pbmRleC5qc1wiKS5OZXN0ZWRQcmVsb2FkUmVjb3JkIHwgc3RyaW5nIHwgQXJyYXk8c3RyaW5nIHwgaW1wb3J0KFwiLi4vZGF0YWJhc2UvcXVlcnkvaW5kZXguanNcIikuTmVzdGVkUHJlbG9hZFJlY29yZD59IFtwcmVsb2FkXSAtIFJlbGF0aW9uc2hpcCBwcmVsb2FkIHRyZWUuXG4gKiBAcHJvcGVydHkge3N0cmluZyB8IHN0cmluZ1tdIHwgUmVjb3JkPHN0cmluZywgYm9vbGVhbiB8IHtyZWxhdGlvbnNoaXA/OiBzdHJpbmcsIHdoZXJlPzogUmVjb3JkPHN0cmluZywgRnJvbnRlbmRNb2RlbFRyYW5zcG9ydFZhbHVlPn0+fSBbd2l0aENvdW50XSAtIEFzc29jaWF0aW9uIGNvdW50IHNwZWMuXG4gKiBAcHJvcGVydHkge3N0cmluZ1tdIHwgUmVjb3JkPHN0cmluZywgc3RyaW5nW10+fSBbYWJpbGl0aWVzXSAtIEFiaWxpdHkgYWN0aW9ucyB0byBjb21wdXRlIHBlciByZWNvcmQuXG4gKiBAcHJvcGVydHkge3N0cmluZyB8IEFycmF5PHN0cmluZyB8IFJlY29yZDxzdHJpbmcsIEZyb250ZW5kTW9kZWxUcmFuc3BvcnRWYWx1ZT4+IHwgUmVjb3JkPHN0cmluZywgRnJvbnRlbmRNb2RlbFRyYW5zcG9ydFZhbHVlPn0gW3F1ZXJ5RGF0YV0gLSBCYWNrZW5kIHF1ZXJ5IGRhdGEgbmFtZXMvc3BlYy5cbiAqL1xuLyoqXG4gKiBEZWZpbmVzIHRoaXMgdHlwZWRlZi5cbiAqIEB0eXBlZGVmIHtGcm9udGVuZE1vZGVsUHJvamVjdGlvbk9wdGlvbnMgJiB7cXVlcnk/OiBGcm9udGVuZE1vZGVsUXVlcnk8dHlwZW9mIGltcG9ydChcIi4vYmFzZS5qc1wiKS5kZWZhdWx0Pn19IEZyb250ZW5kTW9kZWxFdmVudE9wdGlvbnNPYmplY3RcbiAqL1xuLyoqXG4gKiBGcm9udGVuZE1vZGVsRXZlbnRPcHRpb25zIHR5cGUuXG4gKiBAdHlwZWRlZiB7RnJvbnRlbmRNb2RlbEV2ZW50T3B0aW9uc09iamVjdCB8IEZyb250ZW5kTW9kZWxRdWVyeTx0eXBlb2YgaW1wb3J0KFwiLi9iYXNlLmpzXCIpLmRlZmF1bHQ+fSBGcm9udGVuZE1vZGVsRXZlbnRPcHRpb25zXG4gKi9cbi8qKlxuICogRnJvbnRlbmRNb2RlbFByb2plY3Rpb25QYXlsb2FkIHR5cGUuXG4gKiBAdHlwZWRlZiB7b2JqZWN0fSBGcm9udGVuZE1vZGVsUHJvamVjdGlvblBheWxvYWRcbiAqIEBwcm9wZXJ0eSB7UmVjb3JkPHN0cmluZywgc3RyaW5nW10+fSBbc2VsZWN0XSAtIE5vcm1hbGl6ZWQgc2VsZWN0IG1hcC5cbiAqIEBwcm9wZXJ0eSB7UmVjb3JkPHN0cmluZywgc3RyaW5nW10+fSBbc2VsZWN0c0V4dHJhXSAtIE5vcm1hbGl6ZWQgZXh0cmEgc2VsZWN0IG1hcC5cbiAqIEBwcm9wZXJ0eSB7aW1wb3J0KFwiLi4vZGF0YWJhc2UvcXVlcnkvaW5kZXguanNcIikuTmVzdGVkUHJlbG9hZFJlY29yZH0gW3ByZWxvYWRdIC0gTm9ybWFsaXplZCBwcmVsb2FkIHRyZWUuXG4gKiBAcHJvcGVydHkge0Zyb250ZW5kTW9kZWxXaXRoQ291bnRQYXlsb2FkRW50cnlbXX0gW3dpdGhDb3VudF0gLSBOb3JtYWxpemVkIGNvdW50IHNwZWNzLlxuICogQHByb3BlcnR5IHtGcm9udGVuZE1vZGVsQWJpbGl0aWVzUGF5bG9hZEVudHJ5W119IFthYmlsaXRpZXNdIC0gTm9ybWFsaXplZCBhYmlsaXR5IHNwZWNzLlxuICogQHByb3BlcnR5IHtGcm9udGVuZE1vZGVsVHJhbnNwb3J0VmFsdWV9IFtxdWVyeURhdGFdIC0gTm9ybWFsaXplZCBxdWVyeURhdGEgc3BlYy5cbiAqL1xuLyoqXG4gKiBGcm9udGVuZE1vZGVsRXZlbnRGaWx0ZXJQYXlsb2FkIHR5cGUuXG4gKiBAdHlwZWRlZiB7b2JqZWN0fSBGcm9udGVuZE1vZGVsRXZlbnRGaWx0ZXJQYXlsb2FkXG4gKiBAcHJvcGVydHkge1JlY29yZDxzdHJpbmcsIEZyb250ZW5kTW9kZWxUcmFuc3BvcnRWYWx1ZT59IFtqb2luc10gLSBSZWxhdGlvbnNoaXAgam9pbnMgbmVlZGVkIGZvciBtYXRjaGluZy5cbiAqIEBwcm9wZXJ0eSB7RnJvbnRlbmRNb2RlbFNlYXJjaFtdfSBbc2VhcmNoZXNdIC0gU2VhcmNoIHByZWRpY2F0ZXMgbmVlZGVkIGZvciBtYXRjaGluZy5cbiAqIEBwcm9wZXJ0eSB7UmVjb3JkPHN0cmluZywgRnJvbnRlbmRNb2RlbFRyYW5zcG9ydFZhbHVlPn0gW3doZXJlXSAtIFN0cnVjdHVyZWQgd2hlcmUgcHJlZGljYXRlcyBuZWVkZWQgZm9yIG1hdGNoaW5nLlxuICovXG4vKipcbiAqIERlZmluZXMgdGhpcyB0eXBlZGVmLlxuICogQHR5cGVkZWYge0Zyb250ZW5kTW9kZWxFdmVudEZpbHRlclBheWxvYWQgJiB7a2V5OiBzdHJpbmd9fSBGcm9udGVuZE1vZGVsRXZlbnRGaWx0ZXJQYXlsb2FkRW50cnlcbiAqL1xuLyoqXG4gKiBGcm9udGVuZE1vZGVsRXZlbnRPcHRpb25zUGF5bG9hZCB0eXBlLlxuICogQHR5cGVkZWYge29iamVjdH0gRnJvbnRlbmRNb2RlbEV2ZW50T3B0aW9uc1BheWxvYWRcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nIHwgbnVsbH0gZXZlbnRGaWx0ZXJLZXkgLSBTdGFibGUgZXZlbnQgZmlsdGVyIGtleSwgb3IgbnVsbCB3aGVuIG5vIGZpbHRlciBpcyBwcmVzZW50LlxuICogQHByb3BlcnR5IHtGcm9udGVuZE1vZGVsRXZlbnRGaWx0ZXJQYXlsb2FkIHwgbnVsbH0gZXZlbnRGaWx0ZXJQYXlsb2FkIC0gTm9ybWFsaXplZCBldmVudCBmaWx0ZXIgcGF5bG9hZCwgb3IgbnVsbCB3aGVuIHVuZmlsdGVyZWQuXG4gKiBAcHJvcGVydHkge0Zyb250ZW5kTW9kZWxQcm9qZWN0aW9uUGF5bG9hZH0gcHJvamVjdGlvblBheWxvYWQgLSBOb3JtYWxpemVkIGV2ZW50IHNlcmlhbGl6YXRpb24gcHJvamVjdGlvbiBwYXlsb2FkLlxuICovXG5cbi8qKlxuICogUnVucyB0aGUgbm9ybWFsaXplUHJlbG9hZCBoZWxwZXIuXG4gKiBAcGFyYW0ge2ltcG9ydChcIi4uL2RhdGFiYXNlL3F1ZXJ5L2luZGV4LmpzXCIpLk5lc3RlZFByZWxvYWRSZWNvcmQgfCBzdHJpbmcgfCBBcnJheTxzdHJpbmcgfCBpbXBvcnQoXCIuLi9kYXRhYmFzZS9xdWVyeS9pbmRleC5qc1wiKS5OZXN0ZWRQcmVsb2FkUmVjb3JkPiB8IGJvb2xlYW4gfCB1bmRlZmluZWQgfCBudWxsfSBwcmVsb2FkIC0gUHJlbG9hZCBzaG9ydGhhbmQuXG4gKiBAcmV0dXJucyB7aW1wb3J0KFwiLi4vZGF0YWJhc2UvcXVlcnkvaW5kZXguanNcIikuTmVzdGVkUHJlbG9hZFJlY29yZH0gLSBOb3JtYWxpemVkIHByZWxvYWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBub3JtYWxpemVQcmVsb2FkKHByZWxvYWQpIHtcbiAgaWYgKCFwcmVsb2FkKSByZXR1cm4ge31cblxuICBpZiAocHJlbG9hZCA9PT0gdHJ1ZSkgcmV0dXJuIHt9XG5cbiAgaWYgKHR5cGVvZiBwcmVsb2FkID09PSBcInN0cmluZ1wiKSB7XG4gICAgcmV0dXJuIHtbcHJlbG9hZF06IHRydWV9XG4gIH1cblxuICBpZiAoQXJyYXkuaXNBcnJheShwcmVsb2FkKSkge1xuICAgIC8qKlxuICAgICAqIE5vcm1hbGl6ZWQuXG4gICAgICBAdHlwZSB7aW1wb3J0KFwiLi4vZGF0YWJhc2UvcXVlcnkvaW5kZXguanNcIikuTmVzdGVkUHJlbG9hZFJlY29yZH0gKi9cbiAgICBjb25zdCBub3JtYWxpemVkID0ge31cblxuICAgIGZvciAoY29uc3QgZW50cnkgb2YgcHJlbG9hZCkge1xuICAgICAgaWYgKHR5cGVvZiBlbnRyeSA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICBub3JtYWxpemVkW2VudHJ5XSA9IHRydWVcbiAgICAgICAgY29udGludWVcbiAgICAgIH1cblxuICAgICAgaWYgKGlzUGxhaW5PYmplY3QoZW50cnkpKSB7XG4gICAgICAgIG1lcmdlUHJlbG9hZFJlY29yZChub3JtYWxpemVkLCBub3JtYWxpemVQcmVsb2FkKGVudHJ5KSlcbiAgICAgICAgY29udGludWVcbiAgICAgIH1cblxuICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHByZWxvYWQgZW50cnkgdHlwZTogJHt0eXBlb2YgZW50cnl9YClcbiAgICB9XG5cbiAgICByZXR1cm4gbm9ybWFsaXplZFxuICB9XG5cbiAgaWYgKCFpc1BsYWluT2JqZWN0KHByZWxvYWQpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHByZWxvYWQgdHlwZTogJHt0eXBlb2YgcHJlbG9hZH1gKVxuICB9XG5cbiAgLyoqXG4gICAqIE5vcm1hbGl6ZWQuXG4gICAgQHR5cGUge2ltcG9ydChcIi4uL2RhdGFiYXNlL3F1ZXJ5L2luZGV4LmpzXCIpLk5lc3RlZFByZWxvYWRSZWNvcmR9ICovXG4gIGNvbnN0IG5vcm1hbGl6ZWQgPSB7fVxuXG4gIGZvciAoY29uc3QgW3JlbGF0aW9uc2hpcE5hbWUsIHJlbGF0aW9uc2hpcFByZWxvYWRdIG9mIE9iamVjdC5lbnRyaWVzKHByZWxvYWQpKSB7XG4gICAgaWYgKHJlbGF0aW9uc2hpcFByZWxvYWQgPT09IHRydWUgfHwgcmVsYXRpb25zaGlwUHJlbG9hZCA9PT0gZmFsc2UpIHtcbiAgICAgIG5vcm1hbGl6ZWRbcmVsYXRpb25zaGlwTmFtZV0gPSByZWxhdGlvbnNoaXBQcmVsb2FkXG4gICAgICBjb250aW51ZVxuICAgIH1cblxuICAgIGlmICh0eXBlb2YgcmVsYXRpb25zaGlwUHJlbG9hZCA9PT0gXCJzdHJpbmdcIiB8fCBBcnJheS5pc0FycmF5KHJlbGF0aW9uc2hpcFByZWxvYWQpIHx8IGlzUGxhaW5PYmplY3QocmVsYXRpb25zaGlwUHJlbG9hZCkpIHtcbiAgICAgIG5vcm1hbGl6ZWRbcmVsYXRpb25zaGlwTmFtZV0gPSBub3JtYWxpemVQcmVsb2FkKHJlbGF0aW9uc2hpcFByZWxvYWQpXG4gICAgICBjb250aW51ZVxuICAgIH1cblxuICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBwcmVsb2FkIHZhbHVlIGZvciAke3JlbGF0aW9uc2hpcE5hbWV9OiAke3R5cGVvZiByZWxhdGlvbnNoaXBQcmVsb2FkfWApXG4gIH1cblxuICByZXR1cm4gbm9ybWFsaXplZFxufVxuXG4vKipcbiAqIE5vcm1hbGl6ZSB0aGUgc2hvcnRoYW5kIGB3aXRoQ291bnRgIGFyZ3VtZW50IGZyb20gdGhlIGZyb250ZW5kLW1vZGVsXG4gKiBxdWVyeSBBUEkgaW50byB0aGUgc3RyaWN0IGludGVybmFsIGVudHJpZXMgdXNlZCBpbiB0aGUgdHJhbnNwb3J0XG4gKiBwYXlsb2FkLiBTaGFyZXMgdGhlIHNoYXBlIHNlbWFudGljcyB3aXRoIHRoZSBiYWNrZW5kIG5vcm1hbGl6ZXIgaW5cbiAqIGBkYXRhYmFzZS9xdWVyeS93aXRoLWNvdW50LmpzYC5cbiAqIEBwYXJhbSB7c3RyaW5nIHwgc3RyaW5nW10gfCBSZWNvcmQ8c3RyaW5nLCBib29sZWFuIHwge3JlbGF0aW9uc2hpcD86IHN0cmluZywgd2hlcmU/OiBSZWNvcmQ8c3RyaW5nLCA/Pn0+fSBzcGVjXG4gKiBAcmV0dXJucyB7QXJyYXk8e2F0dHJpYnV0ZU5hbWU6IHN0cmluZywgcmVsYXRpb25zaGlwTmFtZTogc3RyaW5nLCB3aGVyZT86IFJlY29yZDxzdHJpbmcsID8+fT59XG4gKi9cbmZ1bmN0aW9uIG5vcm1hbGl6ZVdpdGhDb3VudEZyb250ZW5kKHNwZWMpIHtcbiAgaWYgKHNwZWMgPT0gbnVsbCkgcmV0dXJuIFtdXG5cbiAgaWYgKHR5cGVvZiBzcGVjID09PSBcInN0cmluZ1wiKSB7XG4gICAgcmV0dXJuIFt7YXR0cmlidXRlTmFtZTogYCR7c3BlY31Db3VudGAsIHJlbGF0aW9uc2hpcE5hbWU6IHNwZWN9XVxuICB9XG5cbiAgaWYgKEFycmF5LmlzQXJyYXkoc3BlYykpIHtcbiAgICByZXR1cm4gc3BlYy5mbGF0TWFwKChpdGVtKSA9PiB7XG4gICAgICBpZiAodHlwZW9mIGl0ZW0gIT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGB3aXRoQ291bnQgYXJyYXkgZW50cmllcyBtdXN0IGJlIHN0cmluZ3M7IGdvdCAke3R5cGVvZiBpdGVtfWApXG4gICAgICB9XG5cbiAgICAgIHJldHVybiBbe2F0dHJpYnV0ZU5hbWU6IGAke2l0ZW19Q291bnRgLCByZWxhdGlvbnNoaXBOYW1lOiBpdGVtfV1cbiAgICB9KVxuICB9XG5cbiAgaWYgKCFpc1BsYWluT2JqZWN0KHNwZWMpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHdpdGhDb3VudCBzcGVjOiAke3R5cGVvZiBzcGVjfWApXG4gIH1cblxuICBjb25zdCBlbnRyaWVzID0gW11cblxuICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhzcGVjKSkge1xuICAgIGlmICh2YWx1ZSA9PT0gdHJ1ZSkge1xuICAgICAgZW50cmllcy5wdXNoKHthdHRyaWJ1dGVOYW1lOiBgJHtrZXl9Q291bnRgLCByZWxhdGlvbnNoaXBOYW1lOiBrZXl9KVxuICAgICAgY29udGludWVcbiAgICB9XG5cbiAgICBpZiAodmFsdWUgPT09IGZhbHNlKSBjb250aW51ZVxuXG4gICAgaWYgKGlzUGxhaW5PYmplY3QodmFsdWUpKSB7XG4gICAgICBjb25zdCBvcHRpb25zID0gLyoqXG4gICAgICAgICAgICAgICAgICAgICAgICogTmFycm93cyB0aGUgcnVudGltZSB2YWx1ZSB0byB0aGUgZG9jdW1lbnRlZCB0eXBlLlxuICAgICAgICAgICAgICAgICAgICAgICAgQHR5cGUge3tyZWxhdGlvbnNoaXA/OiBzdHJpbmcsIHdoZXJlPzogUmVjb3JkPHN0cmluZywgPz59fSAqLyAodmFsdWUpXG4gICAgICBlbnRyaWVzLnB1c2goe1xuICAgICAgICBhdHRyaWJ1dGVOYW1lOiBrZXksXG4gICAgICAgIHJlbGF0aW9uc2hpcE5hbWU6IG9wdGlvbnMucmVsYXRpb25zaGlwIHx8IGtleSxcbiAgICAgICAgd2hlcmU6IG9wdGlvbnMud2hlcmVcbiAgICAgIH0pXG4gICAgICBjb250aW51ZVxuICAgIH1cblxuICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCB3aXRoQ291bnQgdmFsdWUgZm9yICR7a2V5fTogJHt0eXBlb2YgdmFsdWV9YClcbiAgfVxuXG4gIHJldHVybiBlbnRyaWVzXG59XG5cbi8qKlxuICogTm9ybWFsaXplIGEgZnJvbnRlbmQgYC5hYmlsaXRpZXMoLi4uKWAgc3BlYyBpbnRvIGEgZmxhdCBsaXN0IG9mXG4gKiBge21vZGVsTmFtZSwgYWN0aW9uc31gIGVudHJpZXMuIEFjY2VwdHMgdGhlIGZsYXQgYWN0aW9ucy1hcnJheVxuICogc2hvcnRoYW5kIChhcHBsaWVzIHRvIHRoZSBxdWVyeSdzIG93biBtb2RlbCBjbGFzcykgYW5kIHRoZSBrZXllZFxuICogYHtNb2RlbE5hbWU6IFthY3Rpb24sIC4uLl19YCBmb3JtIChhcHBsaWVzIHRvIHJlY29yZHMgb2YgdGhhdCBtb2RlbFxuICogY2xhc3MsIHVzZWZ1bCBmb3IgcHJlbG9hZGVkIGNoaWxkcmVuKS5cbiAqIEBwYXJhbSB7c3RyaW5nW10gfCBSZWNvcmQ8c3RyaW5nLCBzdHJpbmdbXT59IHNwZWNcbiAqIEBwYXJhbSB7e2dldE1vZGVsTmFtZTogKCkgPT4gc3RyaW5nfX0gcm9vdE1vZGVsQ2xhc3NcbiAqIEByZXR1cm5zIHtBcnJheTx7bW9kZWxOYW1lOiBzdHJpbmcsIGFjdGlvbnM6IHN0cmluZ1tdfT59XG4gKi9cbmZ1bmN0aW9uIG5vcm1hbGl6ZUFiaWxpdGllc1NwZWMoc3BlYywgcm9vdE1vZGVsQ2xhc3MpIHtcbiAgaWYgKHNwZWMgPT0gbnVsbCkgcmV0dXJuIFtdXG5cbiAgaWYgKEFycmF5LmlzQXJyYXkoc3BlYykpIHtcbiAgICBmb3IgKGNvbnN0IGFjdGlvbiBvZiBzcGVjKSB7XG4gICAgICBpZiAodHlwZW9mIGFjdGlvbiAhPT0gXCJzdHJpbmdcIiB8fCBhY3Rpb24ubGVuZ3RoIDwgMSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYGFiaWxpdGllcyBmbGF0LWZvcm0gYWN0aW9ucyBtdXN0IGJlIG5vbi1lbXB0eSBzdHJpbmdzOyBnb3QgJHt0eXBlb2YgYWN0aW9ufWApXG4gICAgICB9XG4gICAgfVxuXG4gICAgY29uc3Qgcm9vdE1vZGVsTmFtZSA9IHR5cGVvZiByb290TW9kZWxDbGFzcz8uZ2V0TW9kZWxOYW1lID09PSBcImZ1bmN0aW9uXCJcbiAgICAgID8gcm9vdE1vZGVsQ2xhc3MuZ2V0TW9kZWxOYW1lKClcbiAgICAgIDogdW5kZWZpbmVkXG4gICAgaWYgKCFyb290TW9kZWxOYW1lKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJhYmlsaXRpZXMgZmxhdC1mb3JtIHJlcXVpcmVzIGEgcm9vdCBtb2RlbCBjbGFzcyB3aXRoIGdldE1vZGVsTmFtZSgpXCIpXG4gICAgfVxuXG4gICAgcmV0dXJuIFt7YWN0aW9uczogWy4uLnNwZWNdLCBtb2RlbE5hbWU6IHJvb3RNb2RlbE5hbWV9XVxuICB9XG5cbiAgaWYgKCFpc1BsYWluT2JqZWN0KHNwZWMpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIGFiaWxpdGllcyBzcGVjOiAke3R5cGVvZiBzcGVjfWApXG4gIH1cblxuICAvKipcbiAgICogRW50cmllcy5cbiAgICBAdHlwZSB7QXJyYXk8e21vZGVsTmFtZTogc3RyaW5nLCBhY3Rpb25zOiBzdHJpbmdbXX0+fSAqL1xuICBjb25zdCBlbnRyaWVzID0gW11cblxuICBmb3IgKGNvbnN0IFttb2RlbE5hbWUsIGFjdGlvbnNdIG9mIE9iamVjdC5lbnRyaWVzKHNwZWMpKSB7XG4gICAgaWYgKCFBcnJheS5pc0FycmF5KGFjdGlvbnMpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYGFiaWxpdGllc1ske21vZGVsTmFtZX1dIG11c3QgYmUgYW4gYXJyYXkgb2YgYWN0aW9uIG5hbWVzOyBnb3QgJHt0eXBlb2YgYWN0aW9uc31gKVxuICAgIH1cblxuICAgIGNvbnN0IHNhbml0aXplZCA9IGFjdGlvbnMubWFwKChhY3Rpb24pID0+IHtcbiAgICAgIGlmICh0eXBlb2YgYWN0aW9uICE9PSBcInN0cmluZ1wiIHx8IGFjdGlvbi5sZW5ndGggPCAxKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgYWJpbGl0aWVzWyR7bW9kZWxOYW1lfV0gZW50cmllcyBtdXN0IGJlIG5vbi1lbXB0eSBzdHJpbmdzOyBnb3QgJHt0eXBlb2YgYWN0aW9ufWApXG4gICAgICB9XG5cbiAgICAgIHJldHVybiBhY3Rpb25cbiAgICB9KVxuXG4gICAgZW50cmllcy5wdXNoKHthY3Rpb25zOiBzYW5pdGl6ZWQsIG1vZGVsTmFtZX0pXG4gIH1cblxuICByZXR1cm4gZW50cmllc1xufVxuXG4vKipcbiAqIFJ1bnMgbWVyZ2UgcHJlbG9hZCByZWNvcmQuXG4gKiBAcGFyYW0ge2ltcG9ydChcIi4uL2RhdGFiYXNlL3F1ZXJ5L2luZGV4LmpzXCIpLk5lc3RlZFByZWxvYWRSZWNvcmR9IHRhcmdldFByZWxvYWQgLSBFeGlzdGluZyBwcmVsb2FkIGRhdGEuXG4gKiBAcGFyYW0ge2ltcG9ydChcIi4uL2RhdGFiYXNlL3F1ZXJ5L2luZGV4LmpzXCIpLk5lc3RlZFByZWxvYWRSZWNvcmR9IGluY29taW5nUHJlbG9hZCAtIE5ldyBwcmVsb2FkIGRhdGEuXG4gKiBAcmV0dXJucyB7dm9pZH1cbiAqL1xuZnVuY3Rpb24gbWVyZ2VQcmVsb2FkUmVjb3JkKHRhcmdldFByZWxvYWQsIGluY29taW5nUHJlbG9hZCkge1xuICBmb3IgKGNvbnN0IFtyZWxhdGlvbnNoaXBOYW1lLCBpbmNvbWluZ1ZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhpbmNvbWluZ1ByZWxvYWQpKSB7XG4gICAgY29uc3QgZXhpc3RpbmdWYWx1ZSA9IHRhcmdldFByZWxvYWRbcmVsYXRpb25zaGlwTmFtZV1cblxuICAgIGlmIChpbmNvbWluZ1ZhbHVlID09PSBmYWxzZSkge1xuICAgICAgdGFyZ2V0UHJlbG9hZFtyZWxhdGlvbnNoaXBOYW1lXSA9IGZhbHNlXG4gICAgICBjb250aW51ZVxuICAgIH1cblxuICAgIGlmIChpbmNvbWluZ1ZhbHVlID09PSB0cnVlKSB7XG4gICAgICBpZiAoZXhpc3RpbmdWYWx1ZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHRhcmdldFByZWxvYWRbcmVsYXRpb25zaGlwTmFtZV0gPSB0cnVlXG4gICAgICB9XG4gICAgICBjb250aW51ZVxuICAgIH1cblxuICAgIGlmICghaXNQbGFpbk9iamVjdChpbmNvbWluZ1ZhbHVlKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHByZWxvYWQgdmFsdWUgZm9yICR7cmVsYXRpb25zaGlwTmFtZX06ICR7dHlwZW9mIGluY29taW5nVmFsdWV9YClcbiAgICB9XG5cbiAgICBpZiAoaXNQbGFpbk9iamVjdChleGlzdGluZ1ZhbHVlKSkge1xuICAgICAgbWVyZ2VQcmVsb2FkUmVjb3JkKFxuICAgICAgICAvKipcbiAgICAgICAgICogTmFycm93cyB0aGUgcnVudGltZSB2YWx1ZSB0byB0aGUgZG9jdW1lbnRlZCB0eXBlLlxuICAgICAgICAgIEB0eXBlIHtpbXBvcnQoXCIuLi9kYXRhYmFzZS9xdWVyeS9pbmRleC5qc1wiKS5OZXN0ZWRQcmVsb2FkUmVjb3JkfSAqLyAoZXhpc3RpbmdWYWx1ZSksXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBOYXJyb3dzIHRoZSBydW50aW1lIHZhbHVlIHRvIHRoZSBkb2N1bWVudGVkIHR5cGUuXG4gICAgICAgICAgQHR5cGUge2ltcG9ydChcIi4uL2RhdGFiYXNlL3F1ZXJ5L2luZGV4LmpzXCIpLk5lc3RlZFByZWxvYWRSZWNvcmR9ICovIChpbmNvbWluZ1ZhbHVlKVxuICAgICAgKVxuICAgICAgY29udGludWVcbiAgICB9XG5cbiAgICB0YXJnZXRQcmVsb2FkW3JlbGF0aW9uc2hpcE5hbWVdID0gbm9ybWFsaXplUHJlbG9hZChpbmNvbWluZ1ZhbHVlKVxuICB9XG59XG5cbi8qKlxuICogUnVucyBub3JtYWxpemUgc2VsZWN0LlxuICogQHBhcmFtIHs/fSBzZWxlY3QgLSBTZWxlY3QgcGF5bG9hZC5cbiAqIEBwYXJhbSB7c3RyaW5nIHwgbnVsbH0gW3Jvb3RNb2RlbE5hbWVdIC0gT3B0aW9uYWwgcm9vdCBtb2RlbCBuYW1lIGZvciBzaG9ydGhhbmQgc2VsZWN0IHBheWxvYWRzLlxuICogQHJldHVybnMge1JlY29yZDxzdHJpbmcsIHN0cmluZ1tdPn0gLSBOb3JtYWxpemVkIG1vZGVsLW5hbWUga2V5ZWQgc2VsZWN0IHJlY29yZC5cbiAqL1xuZnVuY3Rpb24gbm9ybWFsaXplU2VsZWN0KHNlbGVjdCwgcm9vdE1vZGVsTmFtZSA9IG51bGwpIHtcbiAgaWYgKCFzZWxlY3QpIHJldHVybiB7fVxuXG4gIGlmICh0eXBlb2Ygc2VsZWN0ID09PSBcInN0cmluZ1wiKSB7XG4gICAgaWYgKCFyb290TW9kZWxOYW1lKSB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIHNlbGVjdCBzaG9ydGhhbmQgd2l0aG91dCByb290IG1vZGVsIG5hbWVcIilcblxuICAgIHJldHVybiB7W3Jvb3RNb2RlbE5hbWVdOiBbc2VsZWN0XX1cbiAgfVxuXG4gIGlmIChBcnJheS5pc0FycmF5KHNlbGVjdCkpIHtcbiAgICBpZiAoIXJvb3RNb2RlbE5hbWUpIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgc2VsZWN0IHNob3J0aGFuZCB3aXRob3V0IHJvb3QgbW9kZWwgbmFtZVwiKVxuXG4gICAgZm9yIChjb25zdCBhdHRyaWJ1dGVOYW1lIG9mIHNlbGVjdCkge1xuICAgICAgaWYgKHR5cGVvZiBhdHRyaWJ1dGVOYW1lICE9PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBzZWxlY3QgYXR0cmlidXRlIGZvciAke3Jvb3RNb2RlbE5hbWV9OiAke3R5cGVvZiBhdHRyaWJ1dGVOYW1lfWApXG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHtbcm9vdE1vZGVsTmFtZV06IEFycmF5LmZyb20obmV3IFNldChzZWxlY3QpKX1cbiAgfVxuXG4gIGlmICghaXNQbGFpbk9iamVjdChzZWxlY3QpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHNlbGVjdCB0eXBlOiAke3R5cGVvZiBzZWxlY3R9YClcbiAgfVxuXG4gIC8qKlxuICAgKiBOb3JtYWxpemVkLlxuICAgIEB0eXBlIHtSZWNvcmQ8c3RyaW5nLCBzdHJpbmdbXT59ICovXG4gIGNvbnN0IG5vcm1hbGl6ZWQgPSB7fVxuXG4gIGZvciAoY29uc3QgW21vZGVsTmFtZSwgc2VsZWN0aW9uXSBvZiBPYmplY3QuZW50cmllcyhzZWxlY3QpKSB7XG4gICAgaWYgKHR5cGVvZiBzZWxlY3Rpb24gPT09IFwic3RyaW5nXCIpIHtcbiAgICAgIG5vcm1hbGl6ZWRbbW9kZWxOYW1lXSA9IFtzZWxlY3Rpb25dXG4gICAgICBjb250aW51ZVxuICAgIH1cblxuICAgIGlmICghQXJyYXkuaXNBcnJheShzZWxlY3Rpb24pKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgc2VsZWN0IHZhbHVlIGZvciAke21vZGVsTmFtZX06ICR7dHlwZW9mIHNlbGVjdGlvbn1gKVxuICAgIH1cblxuICAgIGZvciAoY29uc3QgYXR0cmlidXRlTmFtZSBvZiBzZWxlY3Rpb24pIHtcbiAgICAgIGlmICh0eXBlb2YgYXR0cmlidXRlTmFtZSAhPT0gXCJzdHJpbmdcIikge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgc2VsZWN0IGF0dHJpYnV0ZSBmb3IgJHttb2RlbE5hbWV9OiAke3R5cGVvZiBhdHRyaWJ1dGVOYW1lfWApXG4gICAgICB9XG4gICAgfVxuXG4gICAgbm9ybWFsaXplZFttb2RlbE5hbWVdID0gQXJyYXkuZnJvbShuZXcgU2V0KHNlbGVjdGlvbikpXG4gIH1cblxuICByZXR1cm4gbm9ybWFsaXplZFxufVxuXG4vKipcbiAqIFJ1bnMgbWVyZ2Ugc2VsZWN0IHJlY29yZC5cbiAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgc3RyaW5nW10+fSB0YXJnZXRTZWxlY3QgLSBFeGlzdGluZyBzZWxlY3QgcmVjb3JkLlxuICogQHBhcmFtIHtSZWNvcmQ8c3RyaW5nLCBzdHJpbmdbXT59IGluY29taW5nU2VsZWN0IC0gSW5jb21pbmcgc2VsZWN0IHJlY29yZC5cbiAqIEByZXR1cm5zIHt2b2lkfVxuICovXG5mdW5jdGlvbiBtZXJnZVNlbGVjdFJlY29yZCh0YXJnZXRTZWxlY3QsIGluY29taW5nU2VsZWN0KSB7XG4gIGZvciAoY29uc3QgW21vZGVsTmFtZSwgaW5jb21pbmdBdHRyaWJ1dGVzXSBvZiBPYmplY3QuZW50cmllcyhpbmNvbWluZ1NlbGVjdCkpIHtcbiAgICBjb25zdCBleGlzdGluZ0F0dHJpYnV0ZXMgPSB0YXJnZXRTZWxlY3RbbW9kZWxOYW1lXSB8fCBbXVxuXG4gICAgdGFyZ2V0U2VsZWN0W21vZGVsTmFtZV0gPSBBcnJheS5mcm9tKG5ldyBTZXQoWy4uLmV4aXN0aW5nQXR0cmlidXRlcywgLi4uaW5jb21pbmdBdHRyaWJ1dGVzXSkpXG4gIH1cbn1cblxuLyoqXG4gKiBSdW5zIHRoZSBub3JtYWxpemVTZWFyY2hPcGVyYXRvciBoZWxwZXIuXG4gKiBAcGFyYW0ge3N0cmluZ30gb3BlcmF0b3IgLSBSYXcgc2VhcmNoIG9wZXJhdG9yLlxuICogQHJldHVybnMge1wiZXFcIiB8IFwibGlrZVwiIHwgXCJub3RFcVwiIHwgXCJndFwiIHwgXCJndGVxXCIgfCBcImx0XCIgfCBcImx0ZXFcIn0gLSBOb3JtYWxpemVkIG9wZXJhdG9yLlxuICovXG5leHBvcnQgZnVuY3Rpb24gbm9ybWFsaXplU2VhcmNoT3BlcmF0b3Iob3BlcmF0b3IpIHtcbiAgY29uc3Qgb3BlcmF0b3JBbGlhc2VzID0ge1xuICAgIFwiPFwiOiBcImx0XCIsXG4gICAgXCI8PVwiOiBcImx0ZXFcIixcbiAgICBcIj5cIjogXCJndFwiLFxuICAgIFwiPj1cIjogXCJndGVxXCJcbiAgfVxuICBjb25zdCBub3JtYWxpemVkT3BlcmF0b3IgPSBvcGVyYXRvckFsaWFzZXNbLyoqXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKiBOYXJyb3dzIHRoZSBydW50aW1lIHZhbHVlIHRvIHRoZSBkb2N1bWVudGVkIHR5cGUuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEB0eXBlIHtcIjxcIiB8IFwiPD1cIiB8IFwiPlwiIHwgXCI+PVwifSAqLyAob3BlcmF0b3IpXSB8fCBvcGVyYXRvclxuICBjb25zdCBzdXBwb3J0ZWRPcGVyYXRvcnMgPSBuZXcgU2V0KFtcImVxXCIsIFwibGlrZVwiLCBcIm5vdEVxXCIsIFwiZ3RcIiwgXCJndGVxXCIsIFwibHRcIiwgXCJsdGVxXCJdKVxuXG4gIGlmICghc3VwcG9ydGVkT3BlcmF0b3JzLmhhcyhub3JtYWxpemVkT3BlcmF0b3IpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBzZWFyY2ggb3BlcmF0b3IgbXVzdCBiZSBvbmUgb2Y6IGVxLCBsaWtlLCBub3RFcSwgZ3QsIGd0ZXEsIGx0LCBsdGVxLCA+LCA+PSwgPCwgPD0gKGdvdDogJHtvcGVyYXRvcn0pYClcbiAgfVxuXG4gIHJldHVybiAvKiogTmFycm93cyB0aGUgcnVudGltZSB2YWx1ZSB0byB0aGUgZG9jdW1lbnRlZCB0eXBlLiBAdHlwZSB7XCJlcVwiIHwgXCJsaWtlXCIgfCBcIm5vdEVxXCIgfCBcImd0XCIgfCBcImd0ZXFcIiB8IFwibHRcIiB8IFwibHRlcVwifSAqLyAobm9ybWFsaXplZE9wZXJhdG9yKVxufVxuXG4vKipcbiAqIFJ1bnMgbWVyZ2Ugam9pbiByZWNvcmQuXG4gKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsID8+fSB0YXJnZXRKb2lucyAtIEV4aXN0aW5nIGpvaW4gcmVjb3JkLlxuICogQHBhcmFtIHtSZWNvcmQ8c3RyaW5nLCA/Pn0gaW5jb21pbmdKb2lucyAtIEluY29taW5nIGpvaW4gcmVjb3JkLlxuICogQHJldHVybnMge3ZvaWR9XG4gKi9cbmZ1bmN0aW9uIG1lcmdlSm9pblJlY29yZCh0YXJnZXRKb2lucywgaW5jb21pbmdKb2lucykge1xuICBmb3IgKGNvbnN0IFtyZWxhdGlvbnNoaXBOYW1lLCBpbmNvbWluZ1ZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhpbmNvbWluZ0pvaW5zKSkge1xuICAgIGNvbnN0IGV4aXN0aW5nVmFsdWUgPSB0YXJnZXRKb2luc1tyZWxhdGlvbnNoaXBOYW1lXVxuXG4gICAgaWYgKGluY29taW5nVmFsdWUgPT09IHRydWUpIHtcbiAgICAgIGlmIChleGlzdGluZ1ZhbHVlID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdGFyZ2V0Sm9pbnNbcmVsYXRpb25zaGlwTmFtZV0gPSB0cnVlXG4gICAgICB9XG4gICAgICBjb250aW51ZVxuICAgIH1cblxuICAgIGlmICghaXNQbGFpbk9iamVjdChpbmNvbWluZ1ZhbHVlKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIGpvaW4gdmFsdWUgZm9yICR7cmVsYXRpb25zaGlwTmFtZX06ICR7dHlwZW9mIGluY29taW5nVmFsdWV9YClcbiAgICB9XG5cbiAgICBpZiAoaXNQbGFpbk9iamVjdChleGlzdGluZ1ZhbHVlKSkge1xuICAgICAgbWVyZ2VKb2luUmVjb3JkKGV4aXN0aW5nVmFsdWUsIGluY29taW5nVmFsdWUpXG4gICAgICBjb250aW51ZVxuICAgIH1cblxuICAgIGlmIChleGlzdGluZ1ZhbHVlID09PSB0cnVlKSB7XG4gICAgICB0YXJnZXRKb2luc1tyZWxhdGlvbnNoaXBOYW1lXSA9IG5vcm1hbGl6ZUpvaW5zKGluY29taW5nVmFsdWUpXG4gICAgICBjb250aW51ZVxuICAgIH1cblxuICAgIHRhcmdldEpvaW5zW3JlbGF0aW9uc2hpcE5hbWVdID0gbm9ybWFsaXplSm9pbnMoaW5jb21pbmdWYWx1ZSlcbiAgfVxufVxuXG4vKipcbiAqIFJ1bnMgdGhlIG5vcm1hbGl6ZUpvaW5zIGhlbHBlci5cbiAqIEBwYXJhbSB7P30gam9pbnMgLSBKb2luIHBheWxvYWQuXG4gKiBAcmV0dXJucyB7UmVjb3JkPHN0cmluZywgPz59IC0gTm9ybWFsaXplZCByZWxhdGlvbnNoaXAgZGVzY3JpcHRvciBqb2lucy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG5vcm1hbGl6ZUpvaW5zKGpvaW5zKSB7XG4gIGlmICgham9pbnMpIHJldHVybiB7fVxuXG4gIGlmIChBcnJheS5pc0FycmF5KGpvaW5zKSkge1xuICAgIC8qKlxuICAgICAqIE5vcm1hbGl6ZWQuXG4gICAgICBAdHlwZSB7UmVjb3JkPHN0cmluZywgPz59ICovXG4gICAgY29uc3Qgbm9ybWFsaXplZCA9IHt9XG5cbiAgICBmb3IgKGNvbnN0IGpvaW5FbnRyeSBvZiBqb2lucykge1xuICAgICAgaWYgKCFpc1BsYWluT2JqZWN0KGpvaW5FbnRyeSkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIGpvaW5zIGVudHJ5IHR5cGU6ICR7dHlwZW9mIGpvaW5FbnRyeX1gKVxuICAgICAgfVxuXG4gICAgICBtZXJnZUpvaW5SZWNvcmQobm9ybWFsaXplZCwgbm9ybWFsaXplSm9pbnMoam9pbkVudHJ5KSlcbiAgICB9XG5cbiAgICByZXR1cm4gbm9ybWFsaXplZFxuICB9XG5cbiAgaWYgKCFpc1BsYWluT2JqZWN0KGpvaW5zKSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBqb2lucyB0eXBlOiAke3R5cGVvZiBqb2luc31gKVxuICB9XG5cbiAgLyoqXG4gICAqIE5vcm1hbGl6ZWQuXG4gICAgQHR5cGUge1JlY29yZDxzdHJpbmcsID8+fSAqL1xuICBjb25zdCBub3JtYWxpemVkID0ge31cblxuICBmb3IgKGNvbnN0IFtyZWxhdGlvbnNoaXBOYW1lLCByZWxhdGlvbnNoaXBKb2luXSBvZiBPYmplY3QuZW50cmllcyhqb2lucykpIHtcbiAgICBpZiAocmVsYXRpb25zaGlwSm9pbiA9PT0gdHJ1ZSkge1xuICAgICAgbm9ybWFsaXplZFtyZWxhdGlvbnNoaXBOYW1lXSA9IHRydWVcbiAgICAgIGNvbnRpbnVlXG4gICAgfVxuXG4gICAgaWYgKGlzUGxhaW5PYmplY3QocmVsYXRpb25zaGlwSm9pbikpIHtcbiAgICAgIG5vcm1hbGl6ZWRbcmVsYXRpb25zaGlwTmFtZV0gPSBub3JtYWxpemVKb2lucyhyZWxhdGlvbnNoaXBKb2luKVxuICAgICAgY29udGludWVcbiAgICB9XG5cbiAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgam9pbiBkZWZpbml0aW9uIGZvciBcIiR7cmVsYXRpb25zaGlwTmFtZX1cIjogJHt0eXBlb2YgcmVsYXRpb25zaGlwSm9pbn1gKVxuICB9XG5cbiAgcmV0dXJuIG5vcm1hbGl6ZWRcbn1cblxuLyoqXG4gKiBGcm9udGVuZE1vZGVsU29ydCB0eXBlLlxuICogQHR5cGVkZWYge29iamVjdH0gRnJvbnRlbmRNb2RlbFNvcnRcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBjb2x1bW4gLSBBdHRyaWJ1dGUgbmFtZSB0byBzb3J0IGJ5LlxuICogQHByb3BlcnR5IHtcImFzY1wiIHwgXCJkZXNjXCJ9IGRpcmVjdGlvbiAtIFNvcnQgZGlyZWN0aW9uLlxuICogQHByb3BlcnR5IHtzdHJpbmdbXX0gcGF0aCAtIFJlbGF0aW9uc2hpcCBwYXRoIGZyb20gcm9vdCBtb2RlbC5cbiAqL1xuXG4vKipcbiAqIEZyb250ZW5kTW9kZWxHcm91cCB0eXBlLlxuICogQHR5cGVkZWYge29iamVjdH0gRnJvbnRlbmRNb2RlbEdyb3VwXG4gKiBAcHJvcGVydHkge3N0cmluZ30gY29sdW1uIC0gQXR0cmlidXRlIG5hbWUgdG8gZ3JvdXAgYnkuXG4gKiBAcHJvcGVydHkge3N0cmluZ1tdfSBwYXRoIC0gUmVsYXRpb25zaGlwIHBhdGggZnJvbSByb290IG1vZGVsLlxuICovXG5cbi8qKlxuICogRnJvbnRlbmRNb2RlbFBsdWNrIHR5cGUuXG4gKiBAdHlwZWRlZiB7b2JqZWN0fSBGcm9udGVuZE1vZGVsUGx1Y2tcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBjb2x1bW4gLSBBdHRyaWJ1dGUgbmFtZSB0byBwbHVjay5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nW119IHBhdGggLSBSZWxhdGlvbnNoaXAgcGF0aCBmcm9tIHJvb3QgbW9kZWwuXG4gKi9cblxuLyoqXG4gKiBSdW5zIG5vcm1hbGl6ZSBzb3J0IGRpcmVjdGlvbi5cbiAqIEBwYXJhbSB7P30gZGlyZWN0aW9uIC0gRGlyZWN0aW9uIHZhbHVlLlxuICogQHJldHVybnMge1wiYXNjXCIgfCBcImRlc2NcIn0gLSBOb3JtYWxpemVkIGRpcmVjdGlvbi5cbiAqL1xuZnVuY3Rpb24gbm9ybWFsaXplU29ydERpcmVjdGlvbihkaXJlY3Rpb24pIHtcbiAgaWYgKHR5cGVvZiBkaXJlY3Rpb24gIT09IFwic3RyaW5nXCIpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgc29ydCBkaXJlY3Rpb24gdHlwZTogJHt0eXBlb2YgZGlyZWN0aW9ufWApXG4gIH1cblxuICBjb25zdCBub3JtYWxpemVkRGlyZWN0aW9uID0gZGlyZWN0aW9uLnRyaW0oKS50b0xvd2VyQ2FzZSgpXG5cbiAgaWYgKG5vcm1hbGl6ZWREaXJlY3Rpb24gIT09IFwiYXNjXCIgJiYgbm9ybWFsaXplZERpcmVjdGlvbiAhPT0gXCJkZXNjXCIpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgc29ydCBkaXJlY3Rpb246ICR7ZGlyZWN0aW9ufWApXG4gIH1cblxuICByZXR1cm4gbm9ybWFsaXplZERpcmVjdGlvblxufVxuXG4vKipcbiAqIENoZWNrIHdoZXRoZXIgYSB2YWx1ZSBpcyBhIHR3by1pdGVtIGBbY29sdW1uLCBkaXJlY3Rpb25dYCBzb3J0IHR1cGxlLlxuICogQHBhcmFtIHs/fSB2YWx1ZSAtIENhbmRpZGF0ZSB0dXBsZS5cbiAqIEByZXR1cm5zIHt2YWx1ZSBpcyBbc3RyaW5nLCBzdHJpbmddfSAtIFdoZXRoZXIgdmFsdWUgaXMgYSBzb3J0IHR1cGxlLlxuICovXG5mdW5jdGlvbiBzb3J0VHVwbGUodmFsdWUpIHtcbiAgaWYgKCFBcnJheS5pc0FycmF5KHZhbHVlKSkgcmV0dXJuIGZhbHNlXG4gIGlmICh2YWx1ZS5sZW5ndGggIT09IDIpIHJldHVybiBmYWxzZVxuICBpZiAodHlwZW9mIHZhbHVlWzBdICE9PSBcInN0cmluZ1wiKSByZXR1cm4gZmFsc2VcbiAgaWYgKHR5cGVvZiB2YWx1ZVsxXSAhPT0gXCJzdHJpbmdcIikgcmV0dXJuIGZhbHNlXG4gIGlmICh2YWx1ZVswXS50cmltKCkubGVuZ3RoIDwgMSkgcmV0dXJuIGZhbHNlXG5cbiAgY29uc3QgZGlyZWN0aW9uID0gdmFsdWVbMV0udHJpbSgpLnRvTG93ZXJDYXNlKClcblxuICByZXR1cm4gZGlyZWN0aW9uID09PSBcImFzY1wiIHx8IGRpcmVjdGlvbiA9PT0gXCJkZXNjXCJcbn1cblxuLyoqXG4gKiBDaGVjayB3aGV0aGVyIGEgdmFsdWUgaXMgYSBzdHJ1Y3R1cmVkIHNvcnQgZGVzY3JpcHRvciB3aXRoIGEgcmVsYXRpb25zaGlwIHBhdGguXG4gKiBAcGFyYW0gez99IHZhbHVlIC0gQ2FuZGlkYXRlIGRlc2NyaXB0b3IuXG4gKiBAcmV0dXJucyB7dmFsdWUgaXMge2NvbHVtbjogc3RyaW5nLCBkaXJlY3Rpb246IHN0cmluZywgcGF0aDogc3RyaW5nW119fSAtIFdoZXRoZXIgdmFsdWUgaXMgYW4gZXhwbGljaXQgc29ydCBkZXNjcmlwdG9yIG9iamVjdC5cbiAqL1xuZnVuY3Rpb24gc29ydERlc2NyaXB0b3IodmFsdWUpIHtcbiAgaWYgKCFpc1BsYWluT2JqZWN0KHZhbHVlKSkgcmV0dXJuIGZhbHNlXG4gIGlmICghKFwiY29sdW1uXCIgaW4gdmFsdWUpIHx8ICEoXCJkaXJlY3Rpb25cIiBpbiB2YWx1ZSkgfHwgIShcInBhdGhcIiBpbiB2YWx1ZSkpIHJldHVybiBmYWxzZVxuICBpZiAodHlwZW9mIHZhbHVlLmNvbHVtbiAhPT0gXCJzdHJpbmdcIikgcmV0dXJuIGZhbHNlXG4gIGlmICh0eXBlb2YgdmFsdWUuZGlyZWN0aW9uICE9PSBcInN0cmluZ1wiKSByZXR1cm4gZmFsc2VcbiAgaWYgKCFBcnJheS5pc0FycmF5KHZhbHVlLnBhdGgpKSByZXR1cm4gZmFsc2VcblxuICByZXR1cm4gdmFsdWUucGF0aC5ldmVyeSgocGF0aEVudHJ5KSA9PiB0eXBlb2YgcGF0aEVudHJ5ID09PSBcInN0cmluZ1wiKVxufVxuXG4vKipcbiAqIFBhcnNlIGEgc3RyaW5nIHNob3J0aGFuZCBpbnRvIGEgc29ydCBkZXNjcmlwdG9yLlxuICogQHBhcmFtIHtzdHJpbmd9IHNvcnRWYWx1ZSAtIFNvcnQgc3RyaW5nLlxuICogQHBhcmFtIHtzdHJpbmdbXX0gW3BhdGhdIC0gUmVsYXRpb25zaGlwIHBhdGguXG4gKiBAcmV0dXJucyB7RnJvbnRlbmRNb2RlbFNvcnR9IC0gTm9ybWFsaXplZCBzb3J0IGRlc2NyaXB0b3IuXG4gKi9cbmZ1bmN0aW9uIHBhcnNlU29ydFN0cmluZyhzb3J0VmFsdWUsIHBhdGggPSBbXSkge1xuICBjb25zdCB0cmltbWVkID0gc29ydFZhbHVlLnRyaW0oKVxuXG4gIGlmICh0cmltbWVkLmxlbmd0aCA8IDEpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJzb3J0IHZhbHVlIG11c3QgYmUgYSBub24tZW1wdHkgc3RyaW5nXCIpXG4gIH1cblxuICBpZiAodHJpbW1lZC5zdGFydHNXaXRoKFwiLVwiKSkge1xuICAgIGNvbnN0IGNvbHVtbiA9IHRyaW1tZWQuc2xpY2UoMSkudHJpbSgpXG5cbiAgICBpZiAoY29sdW1uLmxlbmd0aCA8IDEpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBzb3J0IGRlZmluaXRpb246ICR7c29ydFZhbHVlfWApXG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGNvbHVtbixcbiAgICAgIGRpcmVjdGlvbjogXCJkZXNjXCIsXG4gICAgICBwYXRoOiBbLi4ucGF0aF1cbiAgICB9XG4gIH1cblxuICBjb25zdCBzb3J0UGFydHMgPSB0cmltbWVkLnNwbGl0KC9cXHMrLykuZmlsdGVyKEJvb2xlYW4pXG5cbiAgaWYgKHNvcnRQYXJ0cy5sZW5ndGggPiAyKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHNvcnQgZGVmaW5pdGlvbjogJHtzb3J0VmFsdWV9YClcbiAgfVxuXG4gIGNvbnN0IGNvbHVtbiA9IHNvcnRQYXJ0c1swXVxuXG4gIGlmIChjb2x1bW4ubGVuZ3RoIDwgMSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBzb3J0IGRlZmluaXRpb246ICR7c29ydFZhbHVlfWApXG4gIH1cblxuICBjb25zdCBkaXJlY3Rpb24gPSBzb3J0UGFydHMubGVuZ3RoID09PSAyXG4gICAgPyBub3JtYWxpemVTb3J0RGlyZWN0aW9uKHNvcnRQYXJ0c1sxXSlcbiAgICA6IFwiYXNjXCJcblxuICByZXR1cm4ge1xuICAgIGNvbHVtbixcbiAgICBkaXJlY3Rpb24sXG4gICAgcGF0aDogWy4uLnBhdGhdXG4gIH1cbn1cblxuLyoqXG4gKiBQYXJzZSBhIHR1cGxlIHNob3J0aGFuZCBpbnRvIGEgc29ydCBkZXNjcmlwdG9yLlxuICogQHBhcmFtIHtbc3RyaW5nLCBzdHJpbmddfSBzb3J0VmFsdWUgLSBTb3J0IHR1cGxlLlxuICogQHBhcmFtIHtzdHJpbmdbXX0gW3BhdGhdIC0gUmVsYXRpb25zaGlwIHBhdGguXG4gKiBAcmV0dXJucyB7RnJvbnRlbmRNb2RlbFNvcnR9IC0gTm9ybWFsaXplZCBzb3J0IGRlc2NyaXB0b3IuXG4gKi9cbmZ1bmN0aW9uIHBhcnNlU29ydFR1cGxlKHNvcnRWYWx1ZSwgcGF0aCA9IFtdKSB7XG4gIGNvbnN0IFtjb2x1bW5WYWx1ZSwgZGlyZWN0aW9uVmFsdWVdID0gc29ydFZhbHVlXG4gIGNvbnN0IGNvbHVtbiA9IGNvbHVtblZhbHVlLnRyaW0oKVxuXG4gIGlmIChjb2x1bW4ubGVuZ3RoIDwgMSkge1xuICAgIHRocm93IG5ldyBFcnJvcihcInNvcnQgdHVwbGUgY29sdW1uIG11c3QgYmUgYSBub24tZW1wdHkgc3RyaW5nXCIpXG4gIH1cblxuICByZXR1cm4ge1xuICAgIGNvbHVtbixcbiAgICBkaXJlY3Rpb246IG5vcm1hbGl6ZVNvcnREaXJlY3Rpb24oZGlyZWN0aW9uVmFsdWUpLFxuICAgIHBhdGg6IFsuLi5wYXRoXVxuICB9XG59XG5cbi8qKlxuICogTm9ybWFsaXplIGEgbmVzdGVkIG9iamVjdCBzb3J0IHBheWxvYWQgaW50byBmbGF0IHNvcnQgZGVzY3JpcHRvcnMuXG4gKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsID8+fSBzb3J0VmFsdWUgLSBOZXN0ZWQgc29ydCBvYmplY3QuXG4gKiBAcGFyYW0ge3N0cmluZ1tdfSBwYXRoIC0gUmVsYXRpb25zaGlwIHBhdGguXG4gKiBAcmV0dXJucyB7RnJvbnRlbmRNb2RlbFNvcnRbXX0gLSBOb3JtYWxpemVkIHNvcnQgZGVzY3JpcHRvcnMuXG4gKi9cbmZ1bmN0aW9uIG5vcm1hbGl6ZVNvcnRPYmplY3Qoc29ydFZhbHVlLCBwYXRoKSB7XG4gIC8qKlxuICAgKiBOb3JtYWxpemVkIHNvcnRzLlxuICAgIEB0eXBlIHtGcm9udGVuZE1vZGVsU29ydFtdfSAqL1xuICBjb25zdCBub3JtYWxpemVkU29ydHMgPSBbXVxuXG4gIGZvciAoY29uc3QgW3NvcnRLZXksIHNvcnRFbnRyeV0gb2YgT2JqZWN0LmVudHJpZXMoc29ydFZhbHVlKSkge1xuICAgIGlmICh0eXBlb2Ygc29ydEVudHJ5ID09PSBcInN0cmluZ1wiKSB7XG4gICAgICBub3JtYWxpemVkU29ydHMucHVzaCh7XG4gICAgICAgIGNvbHVtbjogc29ydEtleSxcbiAgICAgICAgZGlyZWN0aW9uOiBub3JtYWxpemVTb3J0RGlyZWN0aW9uKHNvcnRFbnRyeSksXG4gICAgICAgIHBhdGg6IFsuLi5wYXRoXVxuICAgICAgfSlcbiAgICAgIGNvbnRpbnVlXG4gICAgfVxuXG4gICAgaWYgKHNvcnRUdXBsZShzb3J0RW50cnkpKSB7XG4gICAgICBub3JtYWxpemVkU29ydHMucHVzaChwYXJzZVNvcnRUdXBsZShzb3J0RW50cnksIFsuLi5wYXRoLCBzb3J0S2V5XSkpXG4gICAgICBjb250aW51ZVxuICAgIH1cblxuICAgIGlmIChBcnJheS5pc0FycmF5KHNvcnRFbnRyeSkpIHtcbiAgICAgIGlmIChzb3J0RW50cnkubGVuZ3RoIDwgMSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgc29ydCBkZWZpbml0aW9uIGZvciBcIiR7c29ydEtleX1cIjogZW1wdHkgYXJyYXlgKVxuICAgICAgfVxuXG4gICAgICBmb3IgKGNvbnN0IG5lc3RlZFNvcnRFbnRyeSBvZiBzb3J0RW50cnkpIHtcbiAgICAgICAgaWYgKCFzb3J0VHVwbGUobmVzdGVkU29ydEVudHJ5KSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBzb3J0IGRlZmluaXRpb24gZm9yIFwiJHtzb3J0S2V5fVwiOiBleHBlY3RlZCBbY29sdW1uLCBkaXJlY3Rpb25dIHR1cGxlc2ApXG4gICAgICAgIH1cblxuICAgICAgICBub3JtYWxpemVkU29ydHMucHVzaChwYXJzZVNvcnRUdXBsZShuZXN0ZWRTb3J0RW50cnksIFsuLi5wYXRoLCBzb3J0S2V5XSkpXG4gICAgICB9XG4gICAgICBjb250aW51ZVxuICAgIH1cblxuICAgIGlmIChpc1BsYWluT2JqZWN0KHNvcnRFbnRyeSkpIHtcbiAgICAgIG5vcm1hbGl6ZWRTb3J0cy5wdXNoKC4uLm5vcm1hbGl6ZVNvcnRPYmplY3Qoc29ydEVudHJ5LCBbLi4ucGF0aCwgc29ydEtleV0pKVxuICAgICAgY29udGludWVcbiAgICB9XG5cbiAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgc29ydCBkZWZpbml0aW9uIGZvciBcIiR7c29ydEtleX1cIjogJHt0eXBlb2Ygc29ydEVudHJ5fWApXG4gIH1cblxuICByZXR1cm4gbm9ybWFsaXplZFNvcnRzXG59XG5cbi8qKlxuICogTm9ybWFsaXplIGFueSBzdXBwb3J0ZWQgc29ydCBwYXlsb2FkIGludG8gZmxhdCBzb3J0IGRlc2NyaXB0b3JzLlxuICogQHBhcmFtIHs/fSBzb3J0IC0gU29ydCBwYXlsb2FkLlxuICogQHJldHVybnMge0Zyb250ZW5kTW9kZWxTb3J0W119IC0gTm9ybWFsaXplZCBzb3J0IGRlZmluaXRpb25zLlxuICovXG5leHBvcnQgZnVuY3Rpb24gbm9ybWFsaXplU29ydChzb3J0KSB7XG4gIGlmICghc29ydCkgcmV0dXJuIFtdXG5cbiAgaWYgKHR5cGVvZiBzb3J0ID09PSBcInN0cmluZ1wiKSB7XG4gICAgcmV0dXJuIFtwYXJzZVNvcnRTdHJpbmcoc29ydCldXG4gIH1cblxuICBpZiAoc29ydFR1cGxlKHNvcnQpKSB7XG4gICAgcmV0dXJuIFtwYXJzZVNvcnRUdXBsZShzb3J0KV1cbiAgfVxuXG4gIGlmIChzb3J0RGVzY3JpcHRvcihzb3J0KSkge1xuICAgIHJldHVybiBbe1xuICAgICAgY29sdW1uOiBzb3J0LmNvbHVtbi50cmltKCksXG4gICAgICBkaXJlY3Rpb246IG5vcm1hbGl6ZVNvcnREaXJlY3Rpb24oc29ydC5kaXJlY3Rpb24pLFxuICAgICAgcGF0aDogWy4uLnNvcnQucGF0aF1cbiAgICB9XVxuICB9XG5cbiAgaWYgKGlzUGxhaW5PYmplY3Qoc29ydCkpIHtcbiAgICByZXR1cm4gbm9ybWFsaXplU29ydE9iamVjdChzb3J0LCBbXSlcbiAgfVxuXG4gIGlmIChBcnJheS5pc0FycmF5KHNvcnQpKSB7XG4gICAgLyoqXG4gICAgICogTm9ybWFsaXplZC5cbiAgICAgIEB0eXBlIHtGcm9udGVuZE1vZGVsU29ydFtdfSAqL1xuICAgIGNvbnN0IG5vcm1hbGl6ZWQgPSBbXVxuXG4gICAgZm9yIChjb25zdCBzb3J0RW50cnkgb2Ygc29ydCkge1xuICAgICAgaWYgKHR5cGVvZiBzb3J0RW50cnkgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgbm9ybWFsaXplZC5wdXNoKHBhcnNlU29ydFN0cmluZyhzb3J0RW50cnkpKVxuICAgICAgICBjb250aW51ZVxuICAgICAgfVxuXG4gICAgICBpZiAoc29ydFR1cGxlKHNvcnRFbnRyeSkpIHtcbiAgICAgICAgbm9ybWFsaXplZC5wdXNoKHBhcnNlU29ydFR1cGxlKHNvcnRFbnRyeSkpXG4gICAgICAgIGNvbnRpbnVlXG4gICAgICB9XG5cbiAgICAgIGlmIChzb3J0RGVzY3JpcHRvcihzb3J0RW50cnkpKSB7XG4gICAgICAgIG5vcm1hbGl6ZWQucHVzaCh7XG4gICAgICAgICAgY29sdW1uOiBzb3J0RW50cnkuY29sdW1uLnRyaW0oKSxcbiAgICAgICAgICBkaXJlY3Rpb246IG5vcm1hbGl6ZVNvcnREaXJlY3Rpb24oc29ydEVudHJ5LmRpcmVjdGlvbiksXG4gICAgICAgICAgcGF0aDogWy4uLnNvcnRFbnRyeS5wYXRoXVxuICAgICAgICB9KVxuICAgICAgICBjb250aW51ZVxuICAgICAgfVxuXG4gICAgICBpZiAoaXNQbGFpbk9iamVjdChzb3J0RW50cnkpKSB7XG4gICAgICAgIG5vcm1hbGl6ZWQucHVzaCguLi5ub3JtYWxpemVTb3J0T2JqZWN0KHNvcnRFbnRyeSwgW10pKVxuICAgICAgICBjb250aW51ZVxuICAgICAgfVxuXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgc29ydCBlbnRyeSB0eXBlOiAke3R5cGVvZiBzb3J0RW50cnl9YClcbiAgICB9XG5cbiAgICByZXR1cm4gbm9ybWFsaXplZFxuICB9XG5cbiAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHNvcnQgdHlwZTogJHt0eXBlb2Ygc29ydH1gKVxufVxuXG4vKipcbiAqIFBhcnNlIGEgc3RyaW5nIHNob3J0aGFuZCBpbnRvIGEgZ3JvdXAgZGVzY3JpcHRvci5cbiAqIEBwYXJhbSB7c3RyaW5nfSBncm91cFZhbHVlIC0gR3JvdXAgc3RyaW5nLlxuICogQHBhcmFtIHtzdHJpbmdbXX0gW3BhdGhdIC0gUmVsYXRpb25zaGlwIHBhdGguXG4gKiBAcmV0dXJucyB7RnJvbnRlbmRNb2RlbEdyb3VwfSAtIE5vcm1hbGl6ZWQgZ3JvdXAgZGVzY3JpcHRvci5cbiAqL1xuZnVuY3Rpb24gcGFyc2VHcm91cFN0cmluZyhncm91cFZhbHVlLCBwYXRoID0gW10pIHtcbiAgY29uc3QgdHJpbW1lZCA9IGdyb3VwVmFsdWUudHJpbSgpXG5cbiAgaWYgKCEvXlthLXpBLVpfXVthLXpBLVowLTlfXSokLy50ZXN0KHRyaW1tZWQpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIGdyb3VwIGNvbHVtbjogJHtncm91cFZhbHVlfWApXG4gIH1cblxuICByZXR1cm4ge1xuICAgIGNvbHVtbjogdHJpbW1lZCxcbiAgICBwYXRoOiBbLi4ucGF0aF1cbiAgfVxufVxuXG4vKipcbiAqIENoZWNrIHdoZXRoZXIgYSB2YWx1ZSBpcyBhIHN0cnVjdHVyZWQgY29sdW1uL3BhdGggZGVzY3JpcHRvci5cbiAqIEBwYXJhbSB7P30gdmFsdWUgLSBDYW5kaWRhdGUgZGVzY3JpcHRvci5cbiAqIEByZXR1cm5zIHt2YWx1ZSBpcyB7Y29sdW1uOiBzdHJpbmcsIHBhdGg6IHN0cmluZ1tdfX0gLSBXaGV0aGVyIGNhbmRpZGF0ZSBpcyBhbiBleHBsaWNpdCBjb2x1bW4gZGVzY3JpcHRvciBvYmplY3QuXG4gKi9cbmZ1bmN0aW9uIGNvbHVtblBhdGhEZXNjcmlwdG9yKHZhbHVlKSB7XG4gIGlmICghaXNQbGFpbk9iamVjdCh2YWx1ZSkpIHJldHVybiBmYWxzZVxuICBpZiAoIShcImNvbHVtblwiIGluIHZhbHVlKSB8fCAhKFwicGF0aFwiIGluIHZhbHVlKSkgcmV0dXJuIGZhbHNlXG4gIGlmICh0eXBlb2YgdmFsdWUuY29sdW1uICE9PSBcInN0cmluZ1wiKSByZXR1cm4gZmFsc2VcbiAgaWYgKCFBcnJheS5pc0FycmF5KHZhbHVlLnBhdGgpKSByZXR1cm4gZmFsc2VcblxuICByZXR1cm4gdmFsdWUucGF0aC5ldmVyeSgocGF0aEVudHJ5KSA9PiB0eXBlb2YgcGF0aEVudHJ5ID09PSBcInN0cmluZ1wiKVxufVxuXG4vKipcbiAqIE5vcm1hbGl6ZSBhIG5lc3RlZCBvYmplY3QgY29sdW1uIHByb2plY3Rpb24gcGF5bG9hZCBpbnRvIGZsYXQgZGVzY3JpcHRvcnMuXG4gKiBAdGVtcGxhdGUge3tjb2x1bW46IHN0cmluZywgcGF0aDogc3RyaW5nW119fSBUXG4gKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsID8+fSB2YWx1ZSAtIE5lc3RlZCBwcm9qZWN0aW9uIG9iamVjdC5cbiAqIEBwYXJhbSB7c3RyaW5nW119IHBhdGggLSBSZWxhdGlvbnNoaXAgcGF0aC5cbiAqIEBwYXJhbSB7KGNvbHVtblZhbHVlOiBzdHJpbmcsIHBhdGg/OiBzdHJpbmdbXSkgPT4gVH0gcGFyc2VTdHJpbmcgLSBTdHJpbmcgcHJvamVjdGlvbiBwYXJzZXIuXG4gKiBAcGFyYW0ge3N0cmluZ30gbGFiZWwgLSBQcm9qZWN0aW9uIGxhYmVsIGZvciBlcnJvcnMuXG4gKiBAcmV0dXJucyB7VFtdfSAtIE5vcm1hbGl6ZWQgcHJvamVjdGlvbiBkZXNjcmlwdG9ycy5cbiAqL1xuZnVuY3Rpb24gbm9ybWFsaXplQ29sdW1uUHJvamVjdGlvbk9iamVjdCh2YWx1ZSwgcGF0aCwgcGFyc2VTdHJpbmcsIGxhYmVsKSB7XG4gIC8qKlxuICAgKiBOb3JtYWxpemVkLlxuICAgIEB0eXBlIHtUW119ICovXG4gIGNvbnN0IG5vcm1hbGl6ZWQgPSBbXVxuXG4gIGZvciAoY29uc3QgW3Byb2plY3Rpb25LZXksIHByb2plY3Rpb25FbnRyeV0gb2YgT2JqZWN0LmVudHJpZXModmFsdWUpKSB7XG4gICAgaWYgKHR5cGVvZiBwcm9qZWN0aW9uRW50cnkgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgIG5vcm1hbGl6ZWQucHVzaChwYXJzZVN0cmluZyhwcm9qZWN0aW9uRW50cnksIFsuLi5wYXRoLCBwcm9qZWN0aW9uS2V5XSkpXG4gICAgICBjb250aW51ZVxuICAgIH1cblxuICAgIGlmIChBcnJheS5pc0FycmF5KHByb2plY3Rpb25FbnRyeSkpIHtcbiAgICAgIGlmIChwcm9qZWN0aW9uRW50cnkubGVuZ3RoIDwgMSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgJHtsYWJlbH0gZGVmaW5pdGlvbiBmb3IgXCIke3Byb2plY3Rpb25LZXl9XCI6IGVtcHR5IGFycmF5YClcbiAgICAgIH1cblxuICAgICAgZm9yIChjb25zdCBuZXN0ZWRQcm9qZWN0aW9uRW50cnkgb2YgcHJvamVjdGlvbkVudHJ5KSB7XG4gICAgICAgIGlmICh0eXBlb2YgbmVzdGVkUHJvamVjdGlvbkVudHJ5ICE9PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkICR7bGFiZWx9IGRlZmluaXRpb24gZm9yIFwiJHtwcm9qZWN0aW9uS2V5fVwiOiBleHBlY3RlZCBzdHJpbmcgY29sdW1uc2ApXG4gICAgICAgIH1cblxuICAgICAgICBub3JtYWxpemVkLnB1c2gocGFyc2VTdHJpbmcobmVzdGVkUHJvamVjdGlvbkVudHJ5LCBbLi4ucGF0aCwgcHJvamVjdGlvbktleV0pKVxuICAgICAgfVxuXG4gICAgICBjb250aW51ZVxuICAgIH1cblxuICAgIGlmIChpc1BsYWluT2JqZWN0KHByb2plY3Rpb25FbnRyeSkpIHtcbiAgICAgIG5vcm1hbGl6ZWQucHVzaCguLi5ub3JtYWxpemVDb2x1bW5Qcm9qZWN0aW9uT2JqZWN0KHByb2plY3Rpb25FbnRyeSwgWy4uLnBhdGgsIHByb2plY3Rpb25LZXldLCBwYXJzZVN0cmluZywgbGFiZWwpKVxuICAgICAgY29udGludWVcbiAgICB9XG5cbiAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgJHtsYWJlbH0gZGVmaW5pdGlvbiBmb3IgXCIke3Byb2plY3Rpb25LZXl9XCI6ICR7dHlwZW9mIHByb2plY3Rpb25FbnRyeX1gKVxuICB9XG5cbiAgcmV0dXJuIG5vcm1hbGl6ZWRcbn1cblxuLyoqXG4gKiBOb3JtYWxpemUgYW55IHN1cHBvcnRlZCBncm91cCBwYXlsb2FkIGludG8gZmxhdCBncm91cCBkZXNjcmlwdG9ycy5cbiAqIEBwYXJhbSB7P30gZ3JvdXAgLSBHcm91cCBwYXlsb2FkLlxuICogQHJldHVybnMge0Zyb250ZW5kTW9kZWxHcm91cFtdfSAtIE5vcm1hbGl6ZWQgZ3JvdXAgZGVmaW5pdGlvbnMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBub3JtYWxpemVHcm91cChncm91cCkge1xuICBpZiAoIWdyb3VwKSByZXR1cm4gW11cblxuICBpZiAodHlwZW9mIGdyb3VwID09PSBcInN0cmluZ1wiKSB7XG4gICAgcmV0dXJuIFtwYXJzZUdyb3VwU3RyaW5nKGdyb3VwKV1cbiAgfVxuXG4gIGlmIChjb2x1bW5QYXRoRGVzY3JpcHRvcihncm91cCkpIHtcbiAgICByZXR1cm4gW3tcbiAgICAgIGNvbHVtbjogcGFyc2VHcm91cFN0cmluZyhncm91cC5jb2x1bW4pLmNvbHVtbixcbiAgICAgIHBhdGg6IFsuLi5ncm91cC5wYXRoXVxuICAgIH1dXG4gIH1cblxuICBpZiAoaXNQbGFpbk9iamVjdChncm91cCkpIHtcbiAgICByZXR1cm4gbm9ybWFsaXplQ29sdW1uUHJvamVjdGlvbk9iamVjdChncm91cCwgW10sIHBhcnNlR3JvdXBTdHJpbmcsIFwiZ3JvdXBcIilcbiAgfVxuXG4gIGlmIChBcnJheS5pc0FycmF5KGdyb3VwKSkge1xuICAgIC8qKlxuICAgICAqIE5vcm1hbGl6ZWQuXG4gICAgICBAdHlwZSB7RnJvbnRlbmRNb2RlbEdyb3VwW119ICovXG4gICAgY29uc3Qgbm9ybWFsaXplZCA9IFtdXG5cbiAgICBmb3IgKGNvbnN0IGdyb3VwRW50cnkgb2YgZ3JvdXApIHtcbiAgICAgIGlmICh0eXBlb2YgZ3JvdXBFbnRyeSA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICBub3JtYWxpemVkLnB1c2gocGFyc2VHcm91cFN0cmluZyhncm91cEVudHJ5KSlcbiAgICAgICAgY29udGludWVcbiAgICAgIH1cblxuICAgICAgaWYgKGNvbHVtblBhdGhEZXNjcmlwdG9yKGdyb3VwRW50cnkpKSB7XG4gICAgICAgIG5vcm1hbGl6ZWQucHVzaCh7XG4gICAgICAgICAgY29sdW1uOiBwYXJzZUdyb3VwU3RyaW5nKGdyb3VwRW50cnkuY29sdW1uKS5jb2x1bW4sXG4gICAgICAgICAgcGF0aDogWy4uLmdyb3VwRW50cnkucGF0aF1cbiAgICAgICAgfSlcbiAgICAgICAgY29udGludWVcbiAgICAgIH1cblxuICAgICAgaWYgKGlzUGxhaW5PYmplY3QoZ3JvdXBFbnRyeSkpIHtcbiAgICAgICAgbm9ybWFsaXplZC5wdXNoKC4uLm5vcm1hbGl6ZUNvbHVtblByb2plY3Rpb25PYmplY3QoZ3JvdXBFbnRyeSwgW10sIHBhcnNlR3JvdXBTdHJpbmcsIFwiZ3JvdXBcIikpXG4gICAgICAgIGNvbnRpbnVlXG4gICAgICB9XG5cbiAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBncm91cCBlbnRyeSB0eXBlOiAke3R5cGVvZiBncm91cEVudHJ5fWApXG4gICAgfVxuXG4gICAgcmV0dXJuIG5vcm1hbGl6ZWRcbiAgfVxuXG4gIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBncm91cCB0eXBlOiAke3R5cGVvZiBncm91cH1gKVxufVxuXG4vKipcbiAqIFBhcnNlIGEgc3RyaW5nIHNob3J0aGFuZCBpbnRvIGEgcGx1Y2sgZGVzY3JpcHRvci5cbiAqIEBwYXJhbSB7c3RyaW5nfSBwbHVja1ZhbHVlIC0gUGx1Y2sgc3RyaW5nLlxuICogQHBhcmFtIHtzdHJpbmdbXX0gW3BhdGhdIC0gUmVsYXRpb25zaGlwIHBhdGguXG4gKiBAcmV0dXJucyB7RnJvbnRlbmRNb2RlbFBsdWNrfSAtIE5vcm1hbGl6ZWQgcGx1Y2sgZGVzY3JpcHRvci5cbiAqL1xuZnVuY3Rpb24gcGFyc2VQbHVja1N0cmluZyhwbHVja1ZhbHVlLCBwYXRoID0gW10pIHtcbiAgY29uc3QgdHJpbW1lZCA9IHBsdWNrVmFsdWUudHJpbSgpXG5cbiAgaWYgKCEvXlthLXpBLVpfXVthLXpBLVowLTlfXSokLy50ZXN0KHRyaW1tZWQpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHBsdWNrIGNvbHVtbjogJHtwbHVja1ZhbHVlfWApXG4gIH1cblxuICByZXR1cm4ge1xuICAgIGNvbHVtbjogdHJpbW1lZCxcbiAgICBwYXRoOiBbLi4ucGF0aF1cbiAgfVxufVxuXG4vKipcbiAqIE5vcm1hbGl6ZSBhbnkgc3VwcG9ydGVkIHBsdWNrIHBheWxvYWQgaW50byBmbGF0IHBsdWNrIGRlc2NyaXB0b3JzLlxuICogQHBhcmFtIHs/fSBwbHVjayAtIFBsdWNrIHBheWxvYWQuXG4gKiBAcmV0dXJucyB7RnJvbnRlbmRNb2RlbFBsdWNrW119IC0gTm9ybWFsaXplZCBwbHVjayBkZWZpbml0aW9ucy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG5vcm1hbGl6ZVBsdWNrKHBsdWNrKSB7XG4gIGlmICghcGx1Y2spIHJldHVybiBbXVxuXG4gIGlmICh0eXBlb2YgcGx1Y2sgPT09IFwic3RyaW5nXCIpIHtcbiAgICByZXR1cm4gW3BhcnNlUGx1Y2tTdHJpbmcocGx1Y2spXVxuICB9XG5cbiAgaWYgKGNvbHVtblBhdGhEZXNjcmlwdG9yKHBsdWNrKSkge1xuICAgIHJldHVybiBbe1xuICAgICAgY29sdW1uOiBwYXJzZVBsdWNrU3RyaW5nKHBsdWNrLmNvbHVtbikuY29sdW1uLFxuICAgICAgcGF0aDogWy4uLnBsdWNrLnBhdGhdXG4gICAgfV1cbiAgfVxuXG4gIGlmIChpc1BsYWluT2JqZWN0KHBsdWNrKSkge1xuICAgIHJldHVybiBub3JtYWxpemVDb2x1bW5Qcm9qZWN0aW9uT2JqZWN0KHBsdWNrLCBbXSwgcGFyc2VQbHVja1N0cmluZywgXCJwbHVja1wiKVxuICB9XG5cbiAgaWYgKEFycmF5LmlzQXJyYXkocGx1Y2spKSB7XG4gICAgLyoqXG4gICAgICogTm9ybWFsaXplZC5cbiAgICAgIEB0eXBlIHtGcm9udGVuZE1vZGVsUGx1Y2tbXX0gKi9cbiAgICBjb25zdCBub3JtYWxpemVkID0gW11cblxuICAgIGZvciAoY29uc3QgcGx1Y2tFbnRyeSBvZiBwbHVjaykge1xuICAgICAgaWYgKHR5cGVvZiBwbHVja0VudHJ5ID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIG5vcm1hbGl6ZWQucHVzaChwYXJzZVBsdWNrU3RyaW5nKHBsdWNrRW50cnkpKVxuICAgICAgICBjb250aW51ZVxuICAgICAgfVxuXG4gICAgICBpZiAoY29sdW1uUGF0aERlc2NyaXB0b3IocGx1Y2tFbnRyeSkpIHtcbiAgICAgICAgbm9ybWFsaXplZC5wdXNoKHtcbiAgICAgICAgICBjb2x1bW46IHBhcnNlUGx1Y2tTdHJpbmcocGx1Y2tFbnRyeS5jb2x1bW4pLmNvbHVtbixcbiAgICAgICAgICBwYXRoOiBbLi4ucGx1Y2tFbnRyeS5wYXRoXVxuICAgICAgICB9KVxuICAgICAgICBjb250aW51ZVxuICAgICAgfVxuXG4gICAgICBpZiAoaXNQbGFpbk9iamVjdChwbHVja0VudHJ5KSkge1xuICAgICAgICBub3JtYWxpemVkLnB1c2goLi4ubm9ybWFsaXplQ29sdW1uUHJvamVjdGlvbk9iamVjdChwbHVja0VudHJ5LCBbXSwgcGFyc2VQbHVja1N0cmluZywgXCJwbHVja1wiKSlcbiAgICAgICAgY29udGludWVcbiAgICAgIH1cblxuICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHBsdWNrIGVudHJ5IHR5cGU6ICR7dHlwZW9mIHBsdWNrRW50cnl9YClcbiAgICB9XG5cbiAgICByZXR1cm4gbm9ybWFsaXplZFxuICB9XG5cbiAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHBsdWNrIHR5cGU6ICR7dHlwZW9mIHBsdWNrfWApXG59XG5cbi8qKlxuICogUnVucyBmcm9udGVuZCBtb2RlbCByZXNvdXJjZSBhdHRyaWJ1dGVzLlxuICogQHBhcmFtIHt0eXBlb2YgaW1wb3J0KFwiLi9iYXNlLmpzXCIpLmRlZmF1bHR9IG1vZGVsQ2xhc3MgLSBNb2RlbCBjbGFzcy5cbiAqIEByZXR1cm5zIHtTZXQ8c3RyaW5nPn0gLSBSZXNvdXJjZSBhdHRyaWJ1dGUgbmFtZXMuXG4gKi9cbmZ1bmN0aW9uIGZyb250ZW5kTW9kZWxSZXNvdXJjZUF0dHJpYnV0ZXMobW9kZWxDbGFzcykge1xuICBjb25zdCByZXNvdXJjZUNvbmZpZyA9IC8qKlxuICAgICAgICAgICAgICAgICAgICAgICAgICAqIE5hcnJvd3MgdGhlIHJ1bnRpbWUgdmFsdWUgdG8gdGhlIGRvY3VtZW50ZWQgdHlwZS5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgIEB0eXBlIHtSZWNvcmQ8c3RyaW5nLCA/Pn0gKi8gKG1vZGVsQ2xhc3MucmVzb3VyY2VDb25maWcoKSlcbiAgY29uc3QgYXR0cmlidXRlcyA9IHJlc291cmNlQ29uZmlnLmF0dHJpYnV0ZXNcblxuICBpZiAoQXJyYXkuaXNBcnJheShhdHRyaWJ1dGVzKSkge1xuICAgIHJldHVybiBuZXcgU2V0KGF0dHJpYnV0ZXMpXG4gIH1cblxuICBpZiAoaXNQbGFpbk9iamVjdChhdHRyaWJ1dGVzKSkge1xuICAgIHJldHVybiBuZXcgU2V0KE9iamVjdC5rZXlzKGF0dHJpYnV0ZXMpKVxuICB9XG5cbiAgcmV0dXJuIG5ldyBTZXQoKVxufVxuXG4vKipcbiAqIFJ1bnMgZnJvbnRlbmQgbW9kZWwgcGx1Y2sgdGFyZ2V0IG1vZGVsIGNsYXNzLlxuICogQHBhcmFtIHt0eXBlb2YgaW1wb3J0KFwiLi9iYXNlLmpzXCIpLmRlZmF1bHR9IG1vZGVsQ2xhc3MgLSBSb290IG1vZGVsIGNsYXNzLlxuICogQHBhcmFtIHtzdHJpbmdbXX0gcGF0aCAtIFJlbGF0aW9uc2hpcCBwYXRoLlxuICogQHJldHVybnMge3R5cGVvZiBpbXBvcnQoXCIuL2Jhc2UuanNcIikuZGVmYXVsdH0gLSBUYXJnZXQgbW9kZWwgY2xhc3MgZm9yIHBhdGguXG4gKi9cbmZ1bmN0aW9uIGZyb250ZW5kTW9kZWxQbHVja1RhcmdldE1vZGVsQ2xhc3MobW9kZWxDbGFzcywgcGF0aCkge1xuICBsZXQgdGFyZ2V0TW9kZWxDbGFzcyA9IG1vZGVsQ2xhc3NcblxuICBmb3IgKGNvbnN0IHJlbGF0aW9uc2hpcE5hbWUgb2YgcGF0aCkge1xuICAgIGNvbnN0IHJlbGF0aW9uc2hpcERlZmluaXRpb25zID0gdHlwZW9mIHRhcmdldE1vZGVsQ2xhc3MucmVsYXRpb25zaGlwRGVmaW5pdGlvbnMgPT09IFwiZnVuY3Rpb25cIlxuICAgICAgPyB0YXJnZXRNb2RlbENsYXNzLnJlbGF0aW9uc2hpcERlZmluaXRpb25zKClcbiAgICAgIDoge31cbiAgICBjb25zdCByZWxhdGlvbnNoaXBNb2RlbENsYXNzZXMgPSB0eXBlb2YgdGFyZ2V0TW9kZWxDbGFzcy5yZWxhdGlvbnNoaXBNb2RlbENsYXNzZXMgPT09IFwiZnVuY3Rpb25cIlxuICAgICAgPyB0YXJnZXRNb2RlbENsYXNzLnJlbGF0aW9uc2hpcE1vZGVsQ2xhc3NlcygpXG4gICAgICA6IHt9XG4gICAgY29uc3QgcmVsYXRpb25zaGlwRGVmaW5pdGlvbiA9IHJlbGF0aW9uc2hpcERlZmluaXRpb25zW3JlbGF0aW9uc2hpcE5hbWVdXG4gICAgY29uc3QgcmVsYXRpb25zaGlwVGFyZ2V0TW9kZWxDbGFzcyA9IHJlc29sdmVGcm9udGVuZE1vZGVsQ2xhc3MocmVsYXRpb25zaGlwTW9kZWxDbGFzc2VzW3JlbGF0aW9uc2hpcE5hbWVdKVxuXG4gICAgaWYgKCFyZWxhdGlvbnNoaXBEZWZpbml0aW9uKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFVua25vd24gcGx1Y2sgcmVsYXRpb25zaGlwIFwiJHtyZWxhdGlvbnNoaXBOYW1lfVwiIGZvciAke3RhcmdldE1vZGVsQ2xhc3MubmFtZX1gKVxuICAgIH1cblxuICAgIGlmICghcmVsYXRpb25zaGlwVGFyZ2V0TW9kZWxDbGFzcykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBObyByZWxhdGlvbnNoaXAgbW9kZWwgY2xhc3MgY29uZmlndXJlZCBmb3IgJHt0YXJnZXRNb2RlbENsYXNzLm5hbWV9IyR7cmVsYXRpb25zaGlwTmFtZX1gKVxuICAgIH1cblxuICAgIHRhcmdldE1vZGVsQ2xhc3MgPSByZWxhdGlvbnNoaXBUYXJnZXRNb2RlbENsYXNzXG4gIH1cblxuICByZXR1cm4gdGFyZ2V0TW9kZWxDbGFzc1xufVxuXG4vKipcbiAqIFJ1bnMgdmFsaWRhdGUgcGx1Y2sgZGVmaW5pdGlvbnMuXG4gKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIFBsdWNrIHZhbGlkYXRpb24gYXJncy5cbiAqIEBwYXJhbSB7dHlwZW9mIGltcG9ydChcIi4vYmFzZS5qc1wiKS5kZWZhdWx0fSBhcmdzLm1vZGVsQ2xhc3MgLSBSb290IG1vZGVsIGNsYXNzLlxuICogQHBhcmFtIHtGcm9udGVuZE1vZGVsUGx1Y2tbXX0gYXJncy5wbHVjayAtIFBsdWNrIGRlc2NyaXB0b3JzLlxuICogQHJldHVybnMge0Zyb250ZW5kTW9kZWxQbHVja1tdfSAtIFZhbGlkYXRlZCBwbHVjayBkZXNjcmlwdG9ycy5cbiAqL1xuZnVuY3Rpb24gdmFsaWRhdGVQbHVja0RlZmluaXRpb25zKHttb2RlbENsYXNzLCBwbHVja30pIHtcbiAgcmV0dXJuIHBsdWNrLm1hcCgocGx1Y2tFbnRyeSkgPT4ge1xuICAgIGNvbnN0IHRhcmdldE1vZGVsQ2xhc3MgPSBmcm9udGVuZE1vZGVsUGx1Y2tUYXJnZXRNb2RlbENsYXNzKG1vZGVsQ2xhc3MsIHBsdWNrRW50cnkucGF0aClcbiAgICBjb25zdCB0YXJnZXRBdHRyaWJ1dGVzID0gZnJvbnRlbmRNb2RlbFJlc291cmNlQXR0cmlidXRlcyh0YXJnZXRNb2RlbENsYXNzKVxuXG4gICAgaWYgKCF0YXJnZXRBdHRyaWJ1dGVzLmhhcyhwbHVja0VudHJ5LmNvbHVtbikpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgVW5rbm93biBwbHVjayBjb2x1bW4gXCIke3BsdWNrRW50cnkuY29sdW1ufVwiIGZvciAke3RhcmdldE1vZGVsQ2xhc3MubmFtZX1gKVxuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBjb2x1bW46IHBsdWNrRW50cnkuY29sdW1uLFxuICAgICAgcGF0aDogWy4uLnBsdWNrRW50cnkucGF0aF1cbiAgICB9XG4gIH0pXG59XG5cbi8qKlxuICogUnVucyBzZXJpYWxpemUgZmluZCBjb25kaXRpb25zLlxuICogQHBhcmFtIHtSZWNvcmQ8c3RyaW5nLCA/Pn0gY29uZGl0aW9ucyAtIGZpbmRCeSBjb25kaXRpb25zLlxuICogQHJldHVybnMge3N0cmluZ30gLSBTZXJpYWxpemVkIGNvbmRpdGlvbnMgZm9yIGVycm9yIG1lc3NhZ2VzLlxuICovXG5mdW5jdGlvbiBzZXJpYWxpemVGaW5kQ29uZGl0aW9ucyhjb25kaXRpb25zKSB7XG4gIHRyeSB7XG4gICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KGNvbmRpdGlvbnMpXG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiBcIlt1bnNlcmlhbGl6YWJsZSBjb25kaXRpb25zXVwiXG4gIH1cbn1cblxuLyoqXG4gKiBSdW5zIG5vcm1hbGl6ZSBpbnRlZ2VyIGFyZ3VtZW50LlxuICogQHBhcmFtIHs/fSB2YWx1ZSAtIENhbmRpZGF0ZSBpbnRlZ2VyIHZhbHVlLlxuICogQHBhcmFtIHtzdHJpbmd9IGFyZ3VtZW50TmFtZSAtIEFyZ3VtZW50IG5hbWUgZm9yIGVycm9ycy5cbiAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIC0gVmFsaWRhdGlvbiBvcHRpb25zLlxuICogQHBhcmFtIHtudW1iZXJ9IG9wdGlvbnMubWluIC0gTWluaW11bSBhbGxvd2VkIHZhbHVlLlxuICogQHJldHVybnMge251bWJlcn0gLSBOb3JtYWxpemVkIGludGVnZXIgdmFsdWUuXG4gKi9cbmZ1bmN0aW9uIG5vcm1hbGl6ZUludGVnZXJBcmd1bWVudCh2YWx1ZSwgYXJndW1lbnROYW1lLCB7bWlufSkge1xuICBpZiAodHlwZW9mIHZhbHVlICE9PSBcIm51bWJlclwiIHx8ICFOdW1iZXIuaXNJbnRlZ2VyKHZhbHVlKSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgJHthcmd1bWVudE5hbWV9IG11c3QgYmUgYW4gaW50ZWdlciBudW1iZXJgKVxuICB9XG5cbiAgaWYgKHZhbHVlIDwgbWluKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGAke2FyZ3VtZW50TmFtZX0gbXVzdCBiZSBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gJHttaW59YClcbiAgfVxuXG4gIHJldHVybiB2YWx1ZVxufVxuXG4vKipcbiAqIFJ1bnMgcmV2ZXJzZSBzb3J0IGRpcmVjdGlvbi5cbiAqIEBwYXJhbSB7XCJhc2NcIiB8IFwiZGVzY1wifSBkaXJlY3Rpb24gLSBDdXJyZW50IHNvcnQgZGlyZWN0aW9uLlxuICogQHJldHVybnMge1wiYXNjXCIgfCBcImRlc2NcIn0gLSBSZXZlcnNlZCBkaXJlY3Rpb24uXG4gKi9cbmZ1bmN0aW9uIHJldmVyc2VTb3J0RGlyZWN0aW9uKGRpcmVjdGlvbikge1xuICByZXR1cm4gZGlyZWN0aW9uID09PSBcImFzY1wiID8gXCJkZXNjXCIgOiBcImFzY1wiXG59XG5cbi8qKlxuICogUXVlcnkgd3JhcHBlciBmb3IgZnJvbnRlbmQgbW9kZWwgY29tbWFuZHMuXG4gKiBAdGVtcGxhdGUge3R5cGVvZiBpbXBvcnQoXCIuL2Jhc2UuanNcIikuZGVmYXVsdH0gVFxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBGcm9udGVuZE1vZGVsUXVlcnkge1xuICAvKipcbiAgICogUmFuc2Fjay5cbiAgICBAdHlwZSB7UmVjb3JkPHN0cmluZywgPz5bXX0gKi9cbiAgX3JhbnNhY2sgPSBbXVxuICAvKipcbiAgICogU2VhcmNoZXMuXG4gICAgQHR5cGUge0Zyb250ZW5kTW9kZWxTZWFyY2hbXX0gKi9cbiAgX3NlYXJjaGVzID0gW11cbiAgLyoqXG4gICAqIFNvcnQuXG4gICAgQHR5cGUge0Zyb250ZW5kTW9kZWxTb3J0W119ICovXG4gIF9zb3J0ID0gW11cbiAgLyoqXG4gICAqIEdyb3VwLlxuICAgIEB0eXBlIHtGcm9udGVuZE1vZGVsR3JvdXBbXX0gKi9cbiAgX2dyb3VwID0gW11cblxuICAvKipcbiAgICogUnVucyBjb25zdHJ1Y3Rvci5cbiAgICogQHBhcmFtIHtvYmplY3R9IGFyZ3MgLSBDb25zdHJ1Y3RvciBhcmdzLlxuICAgKiBAcGFyYW0ge1R9IGFyZ3MubW9kZWxDbGFzcyAtIEZyb250ZW5kIG1vZGVsIGNsYXNzLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4uL2RhdGFiYXNlL3F1ZXJ5L2luZGV4LmpzXCIpLk5lc3RlZFByZWxvYWRSZWNvcmR9IFthcmdzLnByZWxvYWRdIC0gUHJlbG9hZCBtYXAuXG4gICAqL1xuICBjb25zdHJ1Y3Rvcih7bW9kZWxDbGFzcywgcHJlbG9hZCA9IHt9fSkge1xuICAgIHRoaXMubW9kZWxDbGFzcyA9IG1vZGVsQ2xhc3NcbiAgICB0aGlzLl9wcmVsb2FkID0gbm9ybWFsaXplUHJlbG9hZChwcmVsb2FkKVxuICAgIHRoaXMuX2pvaW5zID0ge31cbiAgICB0aGlzLl93aGVyZSA9IHt9XG4gICAgdGhpcy5fc2VhcmNoZXMgPSBbXVxuICAgIC8qKlxuICAgICAqIE5hcnJvd3MgdGhlIHJ1bnRpbWUgdmFsdWUgdG8gdGhlIGRvY3VtZW50ZWQgdHlwZS5cbiAgICAgIEB0eXBlIHtSZWNvcmQ8c3RyaW5nLCBzdHJpbmdbXT59ICovXG4gICAgdGhpcy5fc2VsZWN0ID0ge31cbiAgICAvKipcbiAgICAgKiBOYXJyb3dzIHRoZSBydW50aW1lIHZhbHVlIHRvIHRoZSBkb2N1bWVudGVkIHR5cGUuXG4gICAgICBAdHlwZSB7UmVjb3JkPHN0cmluZywgc3RyaW5nW10+fSAqL1xuICAgIHRoaXMuX3NlbGVjdHNFeHRyYSA9IHt9XG4gICAgdGhpcy5fc29ydCA9IFtdXG4gICAgdGhpcy5fZ3JvdXAgPSBbXVxuICAgIHRoaXMuX2Rpc3RpbmN0ID0gZmFsc2VcbiAgICB0aGlzLl9saW1pdCA9IG51bGxcbiAgICB0aGlzLl9vZmZzZXQgPSBudWxsXG4gICAgdGhpcy5fcGFnZSA9IG51bGxcbiAgICB0aGlzLl9wZXJQYWdlID0gbnVsbFxuICAgIC8qKlxuICAgICAqIE5hcnJvd3MgdGhlIHJ1bnRpbWUgdmFsdWUgdG8gdGhlIGRvY3VtZW50ZWQgdHlwZS5cbiAgICAgIEB0eXBlIHtBcnJheTx7YXR0cmlidXRlTmFtZTogc3RyaW5nLCByZWxhdGlvbnNoaXBOYW1lOiBzdHJpbmcsIHdoZXJlPzogUmVjb3JkPHN0cmluZywgPz59Pn0gKi9cbiAgICB0aGlzLl93aXRoQ291bnQgPSBbXVxuICAgIC8qKlxuICAgICAqIE5hcnJvd3MgdGhlIHJ1bnRpbWUgdmFsdWUgdG8gdGhlIGRvY3VtZW50ZWQgdHlwZS5cbiAgICAgIEB0eXBlIHtBcnJheTxzdHJpbmcgfCBSZWNvcmQ8c3RyaW5nLCA/Pj59ICovXG4gICAgdGhpcy5fcXVlcnlEYXRhID0gW11cbiAgICAvKipcbiAgICAgKiBQZXItcmVjb3JkIGFiaWxpdHkgc3BlYy4gTm9ybWFsaXplZCB0byBhIGxpc3Qgb2ZcbiAgICAgKiBge21vZGVsTmFtZSwgYWN0aW9uc31gIGVudHJpZXMg4oCUIG9uZSBlbnRyeSBwZXIgbW9kZWwgdGhhdCBzaG91bGRcbiAgICAgKiBoYXZlIGFiaWxpdHkgcmVzdWx0cyBhdHRhY2hlZC4gVGhlIHJvb3QgcXVlcnkncyBtb2RlbCBjbGFzc1xuICAgICAqIG5hbWUgaXMgaW1wbGljaXQgdmlhIGBcIl9fcm9vdF9fXCJgIHdoZW4gdGhlIGNhbGxlciB1c2VkIHRoZSBmbGF0XG4gICAgICogYXJyYXkgZm9ybS5cbiAgICAgKiBAdHlwZSB7QXJyYXk8e21vZGVsTmFtZTogc3RyaW5nLCBhY3Rpb25zOiBzdHJpbmdbXX0+fVxuICAgICAqL1xuICAgIHRoaXMuX2FiaWxpdGllcyA9IFtdXG4gIH1cblxuICAvKipcbiAgICogVGVsbCB0aGUgYmFja2VuZCB0byBldmFsdWF0ZSBvbmUgb3IgbW9yZSBhYmlsaXR5IGFjdGlvbnMgYWdhaW5zdFxuICAgKiBlYWNoIHJldHVybmVkIHJlY29yZCAoYW5kIGl0cyBwcmVsb2FkZWQgcmVsYXRpb25zLCB3aGVuIGtleWVkIGJ5XG4gICAqIG1vZGVsIG5hbWUpIGFuZCBzaGlwIHRoZSByZXN1bHRzIGJhY2sgc28gdGhlIGZyb250ZW5kIGNhbiByZWFkXG4gICAqIHRoZW0gdmlhIGByZWNvcmQuY2FuKGFjdGlvbilgLlxuICAgKlxuICAgKiBGbGF0IGZvcm0g4oCUIGFwcGxpZXMgdG8gdGhlIHF1ZXJ5J3Mgb3duIG1vZGVsIGNsYXNzOlxuICAgKiAgIGBgYFxuICAgKiAgIGNvbnN0IHRpbWVsb2dzID0gYXdhaXQgVGltZWxvZy53aGVyZSh7dGFza0lkfSlcbiAgICogICAgIC5hYmlsaXRpZXMoW1widXBkYXRlXCIsIFwiZGVzdHJveVwiXSlcbiAgICogICAgIC50b0FycmF5KClcbiAgICogICB0aW1lbG9nc1swXS5jYW4oXCJ1cGRhdGVcIikgLy8g4oaSIGJvb2xlYW5cbiAgICogICBgYGBcbiAgICpcbiAgICogS2V5ZWQgZm9ybSDigJQgdGFyZ2V0cyByZWNvcmRzIGJ5IG1vZGVsIG5hbWUsIHVzZWZ1bCBmb3IgcHJlbG9hZGVkXG4gICAqIGNoaWxkcmVuOlxuICAgKiAgIGBgYFxuICAgKiAgIGNvbnN0IHByb2plY3QgPSBhd2FpdCBQcm9qZWN0XG4gICAqICAgICAucHJlbG9hZChcInRpbWVsb2dzXCIpXG4gICAqICAgICAuYWJpbGl0aWVzKHtUaW1lbG9nOiBbXCJ1cGRhdGVcIiwgXCJkZXN0cm95XCJdfSlcbiAgICogICAgIC5maXJzdCgpXG4gICAqICAgcHJvamVjdC50aW1lbG9ncygpLmxvYWRlZCgpWzBdLmNhbihcInVwZGF0ZVwiKSAvLyDihpIgYm9vbGVhblxuICAgKiAgIGBgYFxuICAgKlxuICAgKiBLZXlzIGluIHRoZSBrZXllZCBmb3JtIGFyZSB0aGUgYmFja2VuZCBtb2RlbCBuYW1lcyAoYXMgcmV0dXJuZWQgYnlcbiAgICogYE1vZGVsQ2xhc3MuZ2V0TW9kZWxOYW1lKClgIC8gdGhlIGBtb2RlbE5hbWVgIGZpZWxkIG9mIHRoZVxuICAgKiBmcm9udGVuZC1tb2RlbCByZXNvdXJjZSBjb25maWcpLiBWYWx1ZXMgYXJlIHRoZSBhYmlsaXR5LWFjdGlvblxuICAgKiBzdHJpbmdzIOKAlCB0eXBpY2FsbHkgYFwidXBkYXRlXCJgIC8gYFwiZGVzdHJveVwiYCAvIGBcImNyZWF0ZVwiYCAvXG4gICAqIGBcInJlYWRcImAsIGJ1dCBhbnkgY3VzdG9tIGFjdGlvbiByZWdpc3RlcmVkIG9uIHRoZSByZXNvdXJjZSdzXG4gICAqIGF1dGhvcml6YXRpb24gYWJpbGl0eSBpcyBhY2NlcHRlZC5cbiAgICogQHBhcmFtIHtzdHJpbmdbXSB8IFJlY29yZDxzdHJpbmcsIHN0cmluZ1tdPn0gc3BlY1xuICAgKiBAcmV0dXJucyB7dGhpc31cbiAgICovXG4gIGFiaWxpdGllcyhzcGVjKSB7XG4gICAgZm9yIChjb25zdCBlbnRyeSBvZiBub3JtYWxpemVBYmlsaXRpZXNTcGVjKHNwZWMsIHRoaXMubW9kZWxDbGFzcykpIHtcbiAgICAgIHRoaXMuX21lcmdlQWJpbGl0eUVudHJ5KGVudHJ5KVxuICAgIH1cblxuICAgIHJldHVybiB0aGlzXG4gIH1cblxuICAvKipcbiAgICogUnVucyBtZXJnZSBhYmlsaXR5IGVudHJ5LlxuICAgKiBAcGFyYW0ge3ttb2RlbE5hbWU6IHN0cmluZywgYWN0aW9uczogc3RyaW5nW119fSBlbnRyeVxuICAgKiBAcmV0dXJucyB7dm9pZH1cbiAgICovXG4gIF9tZXJnZUFiaWxpdHlFbnRyeShlbnRyeSkge1xuICAgIGNvbnN0IGV4aXN0aW5nID0gdGhpcy5fYWJpbGl0aWVzLmZpbmQoKGNhbmRpZGF0ZSkgPT4gY2FuZGlkYXRlLm1vZGVsTmFtZSA9PT0gZW50cnkubW9kZWxOYW1lKVxuXG4gICAgaWYgKCFleGlzdGluZykge1xuICAgICAgdGhpcy5fYWJpbGl0aWVzLnB1c2goe2FjdGlvbnM6IFsuLi5lbnRyeS5hY3Rpb25zXSwgbW9kZWxOYW1lOiBlbnRyeS5tb2RlbE5hbWV9KVxuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgZm9yIChjb25zdCBhY3Rpb24gb2YgZW50cnkuYWN0aW9ucykge1xuICAgICAgaWYgKCFleGlzdGluZy5hY3Rpb25zLmluY2x1ZGVzKGFjdGlvbikpIGV4aXN0aW5nLmFjdGlvbnMucHVzaChhY3Rpb24pXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFRlbGwgdGhlIGJhY2tlbmQgaW5kZXggcXVlcnkgdG8gYXR0YWNoIG9uZSBvciBtb3JlIGFzc29jaWF0aW9uXG4gICAqIGNvdW50cyB0byBlYWNoIHJldHVybmVkIHJlY29yZC4gUGFyc2VzIHRoZSBzYW1lIHNoYXBlcyBhcyB0aGVcbiAgICogYmFja2VuZCBgTW9kZWxDbGFzc1F1ZXJ5I3dpdGhDb3VudGAsIHRoZW4gc2hpcHMgdGhlIG5vcm1hbGl6ZWRcbiAgICogZW50cmllcyBhcyBwYXJ0IG9mIHRoZSBgaW5kZXhgIGNvbW1hbmQgcGF5bG9hZC5cbiAgICogQHBhcmFtIHtzdHJpbmcgfCBzdHJpbmdbXSB8IFJlY29yZDxzdHJpbmcsIGJvb2xlYW4gfCB7cmVsYXRpb25zaGlwPzogc3RyaW5nLCB3aGVyZT86IFJlY29yZDxzdHJpbmcsID8+fT59IHNwZWNcbiAgICogQHJldHVybnMge3RoaXN9XG4gICAqL1xuICB3aXRoQ291bnQoc3BlYykge1xuICAgIGZvciAoY29uc3QgZW50cnkgb2Ygbm9ybWFsaXplV2l0aENvdW50RnJvbnRlbmQoc3BlYykpIHtcbiAgICAgIHRoaXMuX3dpdGhDb3VudC5wdXNoKGVudHJ5KVxuICAgIH1cblxuICAgIHJldHVybiB0aGlzXG4gIH1cblxuICAvKipcbiAgICogUmVxdWVzdCBvbmUgb3IgbW9yZSBiYWNrZW5kIHF1ZXJ5RGF0YSBlbnRyaWVzIGZvciBlYWNoIHJldHVybmVkXG4gICAqIHJlY29yZC4gVGhlIHNwZWMgaXMgYSBuYW1lIG9yIG5lc3RlZC1yZWNvcmQgc2hhcGUgbWF0Y2hpbmcgdGhlXG4gICAqIGBNb2RlbC5xdWVyeURhdGEobmFtZSwgZm4pYCByZWdpc3RyYXRpb25zIG9uIHRoZSBiYWNrZW5kIOKAlCB0aGVcbiAgICogZnJvbnRlbmQgc2hpcHMgb25seSB0aGVzZSBuYW1lczsgdGhlIFNRTCBmcmFnbWVudHMgc3RheSBzZXJ2ZXItXG4gICAqIHNpZGUuIEFsbCByZXN1bHRpbmcgYWxpYXNlcyBhcmUgYXR0YWNoZWQgdG8gdGhlIHJvb3QgcmVjb3JkIGFuZFxuICAgKiByZWFkIGJhY2sgd2l0aCBgcmVjb3JkLnF1ZXJ5RGF0YShhbGlhc05hbWUpYC5cbiAgICogQHBhcmFtIHtzdHJpbmcgfCBBcnJheTxzdHJpbmcgfCBSZWNvcmQ8c3RyaW5nLCA/Pj4gfCBSZWNvcmQ8c3RyaW5nLCA/Pn0gc3BlY1xuICAgKiBAcmV0dXJucyB7dGhpc31cbiAgICovXG4gIHF1ZXJ5RGF0YShzcGVjKSB7XG4gICAgaWYgKHNwZWMgPT0gbnVsbCkgcmV0dXJuIHRoaXNcblxuICAgIHRoaXMuX3F1ZXJ5RGF0YS5wdXNoKC8qKlxuICAgICAgICAgICAgICAgICAgICAgICAgICAqIE5hcnJvd3MgdGhlIHJ1bnRpbWUgdmFsdWUgdG8gdGhlIGRvY3VtZW50ZWQgdHlwZS5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgIEB0eXBlIHs/fSAqLyAoc3BlYykpXG5cbiAgICByZXR1cm4gdGhpc1xuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgd2hlcmUuXG4gICAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgPz59IGNvbmRpdGlvbnMgLSBSb290LW1vZGVsIHdoZXJlIGNvbmRpdGlvbnMuXG4gICAqIEByZXR1cm5zIHt0aGlzfSAtIFF1ZXJ5IHdpdGggbWVyZ2VkIHdoZXJlIGNvbmRpdGlvbnMuXG4gICAqL1xuICB3aGVyZShjb25kaXRpb25zKSB7XG4gICAgdGhpcy5tb2RlbENsYXNzLmFzc2VydEZpbmRCeUNvbmRpdGlvbnMoY29uZGl0aW9ucylcblxuICAgIHRoaXMuX3doZXJlID0ge1xuICAgICAgLi4udGhpcy5fd2hlcmUsXG4gICAgICAuLi5jb25kaXRpb25zXG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXNcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHNjb3BlLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4uL3V0aWxzL21vZGVsLXNjb3BlLmpzXCIpLk1vZGVsU2NvcGVEZXNjcmlwdG9yfSBzY29wZURlc2NyaXB0b3IgLSBTY29wZSBkZXNjcmlwdG9yLlxuICAgKiBAcmV0dXJucyB7dGhpc30gLSBTY29wZWQgcXVlcnkuXG4gICAqL1xuICBzY29wZShzY29wZURlc2NyaXB0b3IpIHtcbiAgICBpZiAoIWlzTW9kZWxTY29wZURlc2NyaXB0b3Ioc2NvcGVEZXNjcmlwdG9yKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwic2NvcGUoKSBleHBlY3RzIGEgZGVzY3JpcHRvciByZXR1cm5lZCBieSBkZWZpbmVTY29wZSguLi4pLnNjb3BlKC4uLilcIilcbiAgICB9XG5cbiAgICBpZiAoc2NvcGVEZXNjcmlwdG9yLm1vZGVsQ2xhc3MgIT09IHRoaXMubW9kZWxDbGFzcykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBDYW5ub3QgYXBwbHkgJHtzY29wZURlc2NyaXB0b3IubW9kZWxDbGFzcy5uYW1lfSBzY29wZSB0byAke3RoaXMubW9kZWxDbGFzcy5uYW1lfSBxdWVyeWApXG4gICAgfVxuXG4gICAgY29uc3Qgc2NvcGVkUXVlcnkgPSAvKipcbiAgICAgICAgICAgICAgICAgICAgICAgICAqIE5hcnJvd3MgdGhlIHJ1bnRpbWUgdmFsdWUgdG8gdGhlIGRvY3VtZW50ZWQgdHlwZS5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgQHR5cGUge3RoaXMgfCB2b2lkfSAqLyAoc2NvcGVEZXNjcmlwdG9yLmNhbGxiYWNrKHtcbiAgICAgIGRyaXZlcjogbnVsbCxcbiAgICAgIG1vZGVsQ2xhc3M6IHRoaXMubW9kZWxDbGFzcyxcbiAgICAgIHF1ZXJ5OiB0aGlzLFxuICAgICAgdGFibGU6IG51bGxcbiAgICB9LCAuLi5zY29wZURlc2NyaXB0b3Iuc2NvcGVBcmdzKSlcblxuICAgIHJldHVybiBzY29wZWRRdWVyeSB8fCB0aGlzXG4gIH1cblxuICAvKipcbiAgICogUnVucyByYW5zYWNrLlxuICAgKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsID8+fSBwYXJhbXMgLSBSYW5zYWNrLXN0eWxlIHBhcmFtcyBoYXNoLiBTdXBwb3J0cyBgc2Aga2V5IGZvciBzb3J0aW5nIChlLmcuLCBge3M6IFwibmFtZSBhc2NcIn1gKS5cbiAgICogQHJldHVybnMge3RoaXN9IC0gUXVlcnkgd2l0aCBSYW5zYWNrIGZpbHRlcnMgYW5kIHNvcnQgYXBwbGllZC5cbiAgICovXG4gIHJhbnNhY2socGFyYW1zKSB7XG4gICAgY29uc3Qge3MsIC4uLmZpbHRlclBhcmFtc30gPSBwYXJhbXNcbiAgICBjb25zdCBoYXNGaWx0ZXJzID0gT2JqZWN0LmtleXMoZmlsdGVyUGFyYW1zKS5sZW5ndGggPiAwXG5cbiAgICBpZiAoaGFzRmlsdGVycykge1xuICAgICAgbm9ybWFsaXplUmFuc2Fja0dyb3VwKHRoaXMubW9kZWxDbGFzcywgZmlsdGVyUGFyYW1zKVxuICAgICAgdGhpcy5fcmFuc2Fjay5wdXNoKGZpbHRlclBhcmFtcylcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIHMgPT09IFwic3RyaW5nXCIgJiYgcy50cmltKCkubGVuZ3RoID4gMCkge1xuICAgICAgY29uc3Qgc29ydHMgPSBwYXJzZVJhbnNhY2tTb3J0KHRoaXMubW9kZWxDbGFzcywgcylcblxuICAgICAgZm9yIChjb25zdCBzb3J0RGVmIG9mIHNvcnRzKSB7XG4gICAgICAgIHRoaXMuc29ydChbW3NvcnREZWYuYXR0cmlidXRlLCBzb3J0RGVmLmRpcmVjdGlvbl1dKVxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0aGlzXG4gIH1cblxuICAvKipcbiAgICogUnVucyBzZWxlY3Qgd2l0aCByZXF1aXJlZCByb290IGF0dHJpYnV0ZXMuXG4gICAqIEBwYXJhbSB7c3RyaW5nW119IFtyZXF1aXJlZEF0dHJpYnV0ZXNdIC0gRXh0cmEgcmVxdWlyZWQgYXR0cmlidXRlcyBmb3IgdGhlIHJvb3QgbW9kZWwuXG4gICAqIEByZXR1cm5zIHtSZWNvcmQ8c3RyaW5nLCBzdHJpbmdbXT59IC0gU2VsZWN0IG1hcCB3aXRoIHJlcXVpcmVkIHJvb3QgYXR0cmlidXRlcyBtZXJnZWQgd2hlbiByb290IHNlbGVjdCBleGlzdHMuXG4gICAqL1xuICBzZWxlY3RXaXRoUmVxdWlyZWRSb290QXR0cmlidXRlcyhyZXF1aXJlZEF0dHJpYnV0ZXMgPSBbXSkge1xuICAgIGNvbnN0IHJvb3RNb2RlbE5hbWUgPSB0aGlzLm1vZGVsQ2xhc3MuZ2V0TW9kZWxOYW1lKClcbiAgICBjb25zdCBzZWxlY3RNYXAgPSAvKipcbiAgICAgICAgICAgICAgICAgICAgICAgKiBOYXJyb3dzIHRoZSBydW50aW1lIHZhbHVlIHRvIHRoZSBkb2N1bWVudGVkIHR5cGUuXG4gICAgICAgICAgICAgICAgICAgICAgICBAdHlwZSB7UmVjb3JkPHN0cmluZywgc3RyaW5nW10+fSAqLyAodGhpcy5fc2VsZWN0KVxuICAgIGNvbnN0IGV4aXN0aW5nUm9vdEF0dHJpYnV0ZXMgPSBzZWxlY3RNYXBbcm9vdE1vZGVsTmFtZV1cblxuICAgIGlmICghZXhpc3RpbmdSb290QXR0cmlidXRlcykge1xuICAgICAgcmV0dXJuIHNlbGVjdE1hcFxuICAgIH1cblxuICAgIGNvbnN0IHJvb3RQcmltYXJ5S2V5ID0gdGhpcy5tb2RlbENsYXNzLnByaW1hcnlLZXkoKVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIC4uLnNlbGVjdE1hcCxcbiAgICAgIFtyb290TW9kZWxOYW1lXTogQXJyYXkuZnJvbShuZXcgU2V0KFtyb290UHJpbWFyeUtleSwgLi4uZXhpc3RpbmdSb290QXR0cmlidXRlcywgLi4ucmVxdWlyZWRBdHRyaWJ1dGVzXSkpXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgcHJlbG9hZC5cbiAgICogQHBhcmFtIHtpbXBvcnQoXCIuLi9kYXRhYmFzZS9xdWVyeS9pbmRleC5qc1wiKS5OZXN0ZWRQcmVsb2FkUmVjb3JkIHwgc3RyaW5nIHwgQXJyYXk8c3RyaW5nIHwgaW1wb3J0KFwiLi4vZGF0YWJhc2UvcXVlcnkvaW5kZXguanNcIikuTmVzdGVkUHJlbG9hZFJlY29yZD59IHByZWxvYWQgLSBQcmVsb2FkIHRvIG1lcmdlLlxuICAgKiBAcmV0dXJucyB7dGhpc30gLSBRdWVyeSB3aXRoIG1lcmdlZCBwcmVsb2Fkcy5cbiAgICovXG4gIHByZWxvYWQocHJlbG9hZCkge1xuICAgIG1lcmdlUHJlbG9hZFJlY29yZCh0aGlzLl9wcmVsb2FkLCBub3JtYWxpemVQcmVsb2FkKHByZWxvYWQpKVxuXG4gICAgcmV0dXJuIHRoaXNcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHNlbGVjdC5cbiAgICogQHBhcmFtIHtSZWNvcmQ8c3RyaW5nLCBzdHJpbmdbXSB8IHN0cmluZz4gfCBzdHJpbmcgfCBzdHJpbmdbXX0gc2VsZWN0IC0gTW9kZWwtYXdhcmUgYXR0cmlidXRlIHNlbGVjdCBtYXAgb3Igcm9vdC1tb2RlbCBzaG9ydGhhbmQuXG4gICAqIEByZXR1cm5zIHt0aGlzfSAtIFF1ZXJ5IHdpdGggbWVyZ2VkIHNlbGVjdGVkIGF0dHJpYnV0ZXMuXG4gICAqL1xuICBzZWxlY3Qoc2VsZWN0KSB7XG4gICAgbWVyZ2VTZWxlY3RSZWNvcmQodGhpcy5fc2VsZWN0LCBub3JtYWxpemVTZWxlY3Qoc2VsZWN0LCB0aGlzLm1vZGVsQ2xhc3MuZ2V0TW9kZWxOYW1lKCkpKVxuXG4gICAgcmV0dXJuIHRoaXNcbiAgfVxuXG4gIC8qKlxuICAgKiBMaWtlIGBzZWxlY3QoLi4uKWAsIGJ1dCBrZWVwcyB0aGUgZGVmYXVsdCBzZXJpYWxpemVkIGF0dHJpYnV0ZXMgYW5kIGxvYWRzXG4gICAqIHRoZSBnaXZlbiBleHRyYXMgaW4gYWRkaXRpb24gKGZvciBleGFtcGxlIGF0dHJpYnV0ZXMgZGVjbGFyZWRcbiAgICogYHNlbGVjdGVkQnlEZWZhdWx0OiBmYWxzZWApLiBLZXllZCBieSBtb2RlbCBuYW1lLCB3aXRoIHJvb3QtbW9kZWwgc2hvcnRoYW5kLlxuICAgKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsIHN0cmluZ1tdIHwgc3RyaW5nPiB8IHN0cmluZyB8IHN0cmluZ1tdfSBzZWxlY3QgLSBFeHRyYSBhdHRyaWJ1dGVzIHRvIGxvYWQsIGtleWVkIGJ5IG1vZGVsIG5hbWUgb3Igcm9vdC1tb2RlbCBzaG9ydGhhbmQuXG4gICAqIEByZXR1cm5zIHt0aGlzfSAtIFF1ZXJ5IHdpdGggbWVyZ2VkIGV4dHJhIHNlbGVjdGVkIGF0dHJpYnV0ZXMuXG4gICAqL1xuICBzZWxlY3RzRXh0cmEoc2VsZWN0KSB7XG4gICAgbWVyZ2VTZWxlY3RSZWNvcmQodGhpcy5fc2VsZWN0c0V4dHJhLCBub3JtYWxpemVTZWxlY3Qoc2VsZWN0LCB0aGlzLm1vZGVsQ2xhc3MuZ2V0TW9kZWxOYW1lKCkpKVxuXG4gICAgcmV0dXJuIHRoaXNcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGpvaW5zLlxuICAgKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsID8+IHwgQXJyYXk8UmVjb3JkPHN0cmluZywgPz4+fSBqb2lucyAtIFJlbGF0aW9uc2hpcCBkZXNjcmlwdG9yIGpvaW5zLlxuICAgKiBAcmV0dXJucyB7dGhpc30gLSBRdWVyeSB3aXRoIG1lcmdlZCBqb2lucy5cbiAgICovXG4gIGpvaW5zKGpvaW5zKSB7XG4gICAgbWVyZ2VKb2luUmVjb3JkKHRoaXMuX2pvaW5zLCBub3JtYWxpemVKb2lucyhqb2lucykpXG5cbiAgICByZXR1cm4gdGhpc1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIHNlYXJjaCByZXN1bHQuXG4gICAqIEBwYXJhbSB7c3RyaW5nW119IHBhdGggLSBSZWxhdGlvbnNoaXAgcGF0aC5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGNvbHVtbiAtIENvbHVtbiBvciBhdHRyaWJ1dGUgbmFtZS5cbiAgICogQHBhcmFtIHtcImVxXCIgfCBcImxpa2VcIiB8IFwibm90RXFcIiB8IFwiZ3RcIiB8IFwiZ3RlcVwiIHwgXCJsdFwiIHwgXCJsdGVxXCIgfCBcIj5cIiB8IFwiPj1cIiB8IFwiPFwiIHwgXCI8PVwifSBvcGVyYXRvciAtIFNlYXJjaCBvcGVyYXRvci5cbiAgICogQHBhcmFtIHs/fSB2YWx1ZSAtIFNlYXJjaCB2YWx1ZS5cbiAgICogQHJldHVybnMge3RoaXN9IC0gUXVlcnkgd2l0aCBhcHBlbmRlZCBzZWFyY2guXG4gICAqL1xuICBzZWFyY2gocGF0aCwgY29sdW1uLCBvcGVyYXRvciwgdmFsdWUpIHtcbiAgICBpZiAoIUFycmF5LmlzQXJyYXkocGF0aCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgc2VhcmNoIHBhdGggbXVzdCBiZSBhbiBhcnJheSwgZ290OiAke3R5cGVvZiBwYXRofWApXG4gICAgfVxuXG4gICAgZm9yIChjb25zdCBwYXRoRW50cnkgb2YgcGF0aCkge1xuICAgICAgaWYgKHR5cGVvZiBwYXRoRW50cnkgIT09IFwic3RyaW5nXCIgfHwgcGF0aEVudHJ5Lmxlbmd0aCA8IDEpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwic2VhcmNoIHBhdGggZW50cmllcyBtdXN0IGJlIG5vbi1lbXB0eSBzdHJpbmdzXCIpXG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHR5cGVvZiBjb2x1bW4gIT09IFwic3RyaW5nXCIgfHwgY29sdW1uLmxlbmd0aCA8IDEpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcInNlYXJjaCBjb2x1bW4gbXVzdCBiZSBhIG5vbi1lbXB0eSBzdHJpbmdcIilcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIG9wZXJhdG9yICE9PSBcInN0cmluZ1wiIHx8IG9wZXJhdG9yLmxlbmd0aCA8IDEpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcInNlYXJjaCBvcGVyYXRvciBtdXN0IGJlIGEgbm9uLWVtcHR5IHN0cmluZ1wiKVxuICAgIH1cblxuICAgIGNvbnN0IG5vcm1hbGl6ZWRPcGVyYXRvciA9IG5vcm1hbGl6ZVNlYXJjaE9wZXJhdG9yKG9wZXJhdG9yKVxuXG4gICAgdGhpcy5fc2VhcmNoZXMucHVzaCh7XG4gICAgICBjb2x1bW4sXG4gICAgICBvcGVyYXRvcjogbm9ybWFsaXplZE9wZXJhdG9yLFxuICAgICAgcGF0aDogWy4uLnBhdGhdLFxuICAgICAgdmFsdWVcbiAgICB9KVxuXG4gICAgcmV0dXJuIHRoaXNcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHNvcnQuXG4gICAqIEBwYXJhbSB7c3RyaW5nIHwgc3RyaW5nW10gfCBbc3RyaW5nLCBzdHJpbmddIHwgQXJyYXk8W3N0cmluZywgc3RyaW5nXT4gfCBSZWNvcmQ8c3RyaW5nLCA/PiB8IEFycmF5PFJlY29yZDxzdHJpbmcsID8+Pn0gc29ydCAtIFNvcnQgZGVmaW5pdGlvbihzKS5cbiAgICogQHJldHVybnMge3RoaXN9IC0gUXVlcnkgd2l0aCBhcHBlbmRlZCBzb3J0IGRlZmluaXRpb25zLlxuICAgKi9cbiAgc29ydChzb3J0KSB7XG4gICAgdGhpcy5fc29ydC5wdXNoKC4uLm5vcm1hbGl6ZVNvcnQoc29ydCkpXG5cbiAgICByZXR1cm4gdGhpc1xuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgb3JkZXIuXG4gICAqIEBwYXJhbSB7c3RyaW5nIHwgc3RyaW5nW10gfCBbc3RyaW5nLCBzdHJpbmddIHwgQXJyYXk8W3N0cmluZywgc3RyaW5nXT4gfCBSZWNvcmQ8c3RyaW5nLCA/PiB8IEFycmF5PFJlY29yZDxzdHJpbmcsID8+Pn0gb3JkZXIgLSBPcmRlciBkZWZpbml0aW9uKHMpLlxuICAgKiBAcmV0dXJucyB7dGhpc30gLSBRdWVyeSB3aXRoIGFwcGVuZGVkIHNvcnQgZGVmaW5pdGlvbnMuXG4gICAqL1xuICBvcmRlcihvcmRlcikge1xuICAgIHJldHVybiB0aGlzLnNvcnQob3JkZXIpXG4gIH1cblxuICAvKipcbiAgICogUnVucyBncm91cC5cbiAgICogQHBhcmFtIHtzdHJpbmcgfCBzdHJpbmdbXSB8IFJlY29yZDxzdHJpbmcsID8+IHwgQXJyYXk8UmVjb3JkPHN0cmluZywgPz4+fSBncm91cCAtIEdyb3VwIGRlZmluaXRpb24ocykuXG4gICAqIEByZXR1cm5zIHt0aGlzfSAtIFF1ZXJ5IHdpdGggYXBwZW5kZWQgZ3JvdXAgZGVmaW5pdGlvbnMuXG4gICAqL1xuICBncm91cChncm91cCkge1xuICAgIHRoaXMuX2dyb3VwLnB1c2goLi4ubm9ybWFsaXplR3JvdXAoZ3JvdXApKVxuXG4gICAgcmV0dXJuIHRoaXNcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGRpc3RpbmN0LlxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFt2YWx1ZV0gLSBXaGV0aGVyIHRvIHJlcXVlc3QgZGlzdGluY3Qgcm93cy5cbiAgICogQHJldHVybnMge3RoaXN9IC0gUXVlcnkgd2l0aCBkaXN0aW5jdCBmbGFnLlxuICAgKi9cbiAgZGlzdGluY3QodmFsdWUgPSB0cnVlKSB7XG4gICAgaWYgKHR5cGVvZiB2YWx1ZSAhPT0gXCJib29sZWFuXCIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgZGlzdGluY3QgbXVzdCBiZSBhIGJvb2xlYW4sIGdvdDogJHt0eXBlb2YgdmFsdWV9YClcbiAgICB9XG5cbiAgICB0aGlzLl9kaXN0aW5jdCA9IHZhbHVlXG5cbiAgICByZXR1cm4gdGhpc1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIGxpbWl0IHJlc3VsdC5cbiAgICogQHBhcmFtIHtudW1iZXJ9IHZhbHVlIC0gTWF4aW11bSBudW1iZXIgb2YgcmVjb3Jkcy5cbiAgICogQHJldHVybnMge3RoaXN9IC0gUXVlcnkgd2l0aCBsaW1pdC5cbiAgICovXG4gIGxpbWl0KHZhbHVlKSB7XG4gICAgdGhpcy5fbGltaXQgPSBub3JtYWxpemVJbnRlZ2VyQXJndW1lbnQodmFsdWUsIFwibGltaXRcIiwge21pbjogMH0pXG4gICAgdGhpcy5fcGFnZSA9IG51bGxcblxuICAgIHJldHVybiB0aGlzXG4gIH1cblxuICAvKipcbiAgICogUnVucyBvZmZzZXQuXG4gICAqIEBwYXJhbSB7bnVtYmVyfSB2YWx1ZSAtIE51bWJlciBvZiByZWNvcmRzIHRvIHNraXAuXG4gICAqIEByZXR1cm5zIHt0aGlzfSAtIFF1ZXJ5IHdpdGggb2Zmc2V0LlxuICAgKi9cbiAgb2Zmc2V0KHZhbHVlKSB7XG4gICAgdGhpcy5fb2Zmc2V0ID0gbm9ybWFsaXplSW50ZWdlckFyZ3VtZW50KHZhbHVlLCBcIm9mZnNldFwiLCB7bWluOiAwfSlcbiAgICB0aGlzLl9wYWdlID0gbnVsbFxuXG4gICAgcmV0dXJuIHRoaXNcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHBhZ2UuXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBwYWdlTnVtYmVyIC0gMS1iYXNlZCBwYWdlIG51bWJlci5cbiAgICogQHJldHVybnMge3RoaXN9IC0gUXVlcnkgd2l0aCBwYWdlIGFwcGxpZWQuXG4gICAqL1xuICBwYWdlKHBhZ2VOdW1iZXIpIHtcbiAgICB0aGlzLl9wYWdlID0gbm9ybWFsaXplSW50ZWdlckFyZ3VtZW50KHBhZ2VOdW1iZXIsIFwicGFnZVwiLCB7bWluOiAxfSlcbiAgICBjb25zdCBwYWdlU2l6ZSA9IHRoaXMuX3BlclBhZ2UgfHwgMzBcblxuICAgIHRoaXMuX2xpbWl0ID0gcGFnZVNpemVcbiAgICB0aGlzLl9vZmZzZXQgPSAodGhpcy5fcGFnZSAtIDEpICogcGFnZVNpemVcblxuICAgIHJldHVybiB0aGlzXG4gIH1cblxuICAvKipcbiAgICogUnVucyBwZXIgcGFnZS5cbiAgICogQHBhcmFtIHtudW1iZXJ9IHBlclBhZ2UgLSBQYWdlIHNpemUuXG4gICAqIEByZXR1cm5zIHt0aGlzfSAtIFF1ZXJ5IHdpdGggcGVyLXBhZ2UgYXBwbGllZC5cbiAgICovXG4gIHBlclBhZ2UocGVyUGFnZSkge1xuICAgIHRoaXMuX3BlclBhZ2UgPSBub3JtYWxpemVJbnRlZ2VyQXJndW1lbnQocGVyUGFnZSwgXCJwZXJQYWdlXCIsIHttaW46IDF9KVxuXG4gICAgaWYgKHRoaXMuX3BhZ2UgIT09IG51bGwpIHtcbiAgICAgIHRoaXMuX2xpbWl0ID0gdGhpcy5fcGVyUGFnZVxuICAgICAgdGhpcy5fb2Zmc2V0ID0gKHRoaXMuX3BhZ2UgLSAxKSAqIHRoaXMuX3BlclBhZ2VcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpc1xuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgY2xvbmUuXG4gICAqIEByZXR1cm5zIHtGcm9udGVuZE1vZGVsUXVlcnk8VD59IC0gQ2xvbmVkIHF1ZXJ5IGluc3RhbmNlLlxuICAgKi9cbiAgY2xvbmUoKSB7XG4gICAgY29uc3QgbmV3UXVlcnkgPSAvKipcbiAgICAgICAgICAgICAgICAgICAgICAqIE5hcnJvd3MgdGhlIHJ1bnRpbWUgdmFsdWUgdG8gdGhlIGRvY3VtZW50ZWQgdHlwZS5cbiAgICAgICAgICAgICAgICAgICAgICAgQHR5cGUge0Zyb250ZW5kTW9kZWxRdWVyeTxUPn0gKi8gKG5ldyBGcm9udGVuZE1vZGVsUXVlcnkoe1xuICAgICAgbW9kZWxDbGFzczogdGhpcy5tb2RlbENsYXNzLFxuICAgICAgcHJlbG9hZDogbm9ybWFsaXplUHJlbG9hZCh0aGlzLl9wcmVsb2FkKVxuICAgIH0pKVxuXG4gICAgbmV3UXVlcnkuX2pvaW5zID0gbm9ybWFsaXplSm9pbnModGhpcy5fam9pbnMpXG4gICAgbmV3UXVlcnkuX3doZXJlID0gey4uLnRoaXMuX3doZXJlfVxuICAgIG5ld1F1ZXJ5Ll9yYW5zYWNrID0gdGhpcy5fcmFuc2Fjay5tYXAoKHJhbnNhY2tQYXJhbXMpID0+ICh7Li4ucmFuc2Fja1BhcmFtc30pKVxuICAgIG5ld1F1ZXJ5Ll9zZWFyY2hlcyA9IHRoaXMuX3NlYXJjaGVzLm1hcCgoc2VhcmNoKSA9PiAoe1xuICAgICAgY29sdW1uOiBzZWFyY2guY29sdW1uLFxuICAgICAgb3BlcmF0b3I6IHNlYXJjaC5vcGVyYXRvcixcbiAgICAgIHBhdGg6IFsuLi5zZWFyY2gucGF0aF0sXG4gICAgICB2YWx1ZTogc2VhcmNoLnZhbHVlXG4gICAgfSkpXG4gICAgbmV3UXVlcnkuX3NlbGVjdCA9IG5vcm1hbGl6ZVNlbGVjdCh0aGlzLl9zZWxlY3QpXG4gICAgbmV3UXVlcnkuX3NlbGVjdHNFeHRyYSA9IG5vcm1hbGl6ZVNlbGVjdCh0aGlzLl9zZWxlY3RzRXh0cmEpXG4gICAgbmV3UXVlcnkuX3NvcnQgPSB0aGlzLl9zb3J0Lm1hcCgoc29ydEVudHJ5KSA9PiAoe1xuICAgICAgY29sdW1uOiBzb3J0RW50cnkuY29sdW1uLFxuICAgICAgZGlyZWN0aW9uOiBzb3J0RW50cnkuZGlyZWN0aW9uLFxuICAgICAgcGF0aDogWy4uLnNvcnRFbnRyeS5wYXRoXVxuICAgIH0pKVxuICAgIG5ld1F1ZXJ5Ll9ncm91cCA9IHRoaXMuX2dyb3VwLm1hcCgoZ3JvdXBFbnRyeSkgPT4gKHtcbiAgICAgIGNvbHVtbjogZ3JvdXBFbnRyeS5jb2x1bW4sXG4gICAgICBwYXRoOiBbLi4uZ3JvdXBFbnRyeS5wYXRoXVxuICAgIH0pKVxuICAgIG5ld1F1ZXJ5Ll9kaXN0aW5jdCA9IHRoaXMuX2Rpc3RpbmN0XG4gICAgbmV3UXVlcnkuX2xpbWl0ID0gdGhpcy5fbGltaXRcbiAgICBuZXdRdWVyeS5fb2Zmc2V0ID0gdGhpcy5fb2Zmc2V0XG4gICAgbmV3UXVlcnkuX3BhZ2UgPSB0aGlzLl9wYWdlXG4gICAgbmV3UXVlcnkuX3BlclBhZ2UgPSB0aGlzLl9wZXJQYWdlXG4gICAgbmV3UXVlcnkuX3dpdGhDb3VudCA9IHRoaXMuX3dpdGhDb3VudC5tYXAoKGVudHJ5KSA9PiAoe1xuICAgICAgYXR0cmlidXRlTmFtZTogZW50cnkuYXR0cmlidXRlTmFtZSxcbiAgICAgIHJlbGF0aW9uc2hpcE5hbWU6IGVudHJ5LnJlbGF0aW9uc2hpcE5hbWUsXG4gICAgICB3aGVyZTogZW50cnkud2hlcmUgPyB7Li4uZW50cnkud2hlcmV9IDogdW5kZWZpbmVkXG4gICAgfSkpXG4gICAgbmV3UXVlcnkuX3F1ZXJ5RGF0YSA9IHRoaXMuX3F1ZXJ5RGF0YS5tYXAoKGVudHJ5KSA9PiAoXG4gICAgICB0eXBlb2YgZW50cnkgPT09IFwic3RyaW5nXCIgPyBlbnRyeSA6IHsuLi5lbnRyeX1cbiAgICApKVxuICAgIG5ld1F1ZXJ5Ll9hYmlsaXRpZXMgPSB0aGlzLl9hYmlsaXRpZXMubWFwKChlbnRyeSkgPT4gKHtcbiAgICAgIGFjdGlvbnM6IFsuLi5lbnRyeS5hY3Rpb25zXSxcbiAgICAgIG1vZGVsTmFtZTogZW50cnkubW9kZWxOYW1lXG4gICAgfSkpXG5cbiAgICByZXR1cm4gbmV3UXVlcnlcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGdldCBtb2RlbCBjbGFzcy5cbiAgICogQHJldHVybnMge1R9IC0gUm9vdCBtb2RlbCBjbGFzcy5cbiAgICovXG4gIGdldE1vZGVsQ2xhc3MoKSB7XG4gICAgcmV0dXJuIHRoaXMubW9kZWxDbGFzc1xuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgcHJlbG9hZCBwYXlsb2FkLlxuICAgKiBAcmV0dXJucyB7UmVjb3JkPHN0cmluZywgPz59IC0gUGF5bG9hZCBwcmVsb2FkIGhhc2ggd2hlbiBwcmVzZW50LlxuICAgKi9cbiAgcHJlbG9hZFBheWxvYWQoKSB7XG4gICAgaWYgKE9iamVjdC5rZXlzKHRoaXMuX3ByZWxvYWQpLmxlbmd0aCA9PT0gMCkgcmV0dXJuIHt9XG5cbiAgICByZXR1cm4ge3ByZWxvYWQ6IHRoaXMuX3ByZWxvYWR9XG4gIH1cblxuICAvKipcbiAgICogUnVucyB3aXRoIGNvdW50IHBheWxvYWQuXG4gICAqIEByZXR1cm5zIHtSZWNvcmQ8c3RyaW5nLCA/Pn0gLSBQYXlsb2FkIHdpdGhDb3VudCBhcnJheSB3aGVuIHByZXNlbnQuXG4gICAqL1xuICB3aXRoQ291bnRQYXlsb2FkKCkge1xuICAgIGlmICh0aGlzLl93aXRoQ291bnQubGVuZ3RoID09PSAwKSByZXR1cm4ge31cblxuICAgIHJldHVybiB7XG4gICAgICB3aXRoQ291bnQ6IHRoaXMuX3dpdGhDb3VudC5tYXAoKGVudHJ5KSA9PiAoe1xuICAgICAgICBhdHRyaWJ1dGVOYW1lOiBlbnRyeS5hdHRyaWJ1dGVOYW1lLFxuICAgICAgICByZWxhdGlvbnNoaXBOYW1lOiBlbnRyeS5yZWxhdGlvbnNoaXBOYW1lLFxuICAgICAgICB3aGVyZTogZW50cnkud2hlcmUgfHwgdW5kZWZpbmVkXG4gICAgICB9KSlcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUnVucyBhYmlsaXRpZXMgcGF5bG9hZC5cbiAgICogQHJldHVybnMge1JlY29yZDxzdHJpbmcsID8+fSAtIFBheWxvYWQgYWJpbGl0aWVzIGFycmF5IHdoZW4gcHJlc2VudC5cbiAgICovXG4gIGFiaWxpdGllc1BheWxvYWQoKSB7XG4gICAgaWYgKHRoaXMuX2FiaWxpdGllcy5sZW5ndGggPT09IDApIHJldHVybiB7fVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGFiaWxpdGllczogdGhpcy5fYWJpbGl0aWVzLm1hcCgoZW50cnkpID0+ICh7XG4gICAgICAgIGFjdGlvbnM6IFsuLi5lbnRyeS5hY3Rpb25zXSxcbiAgICAgICAgbW9kZWxOYW1lOiBlbnRyeS5tb2RlbE5hbWVcbiAgICAgIH0pKVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHF1ZXJ5IGRhdGEgcGF5bG9hZC5cbiAgICogQHJldHVybnMge1JlY29yZDxzdHJpbmcsID8+fSAtIFBheWxvYWQgcXVlcnlEYXRhIHNwZWMgd2hlbiBwcmVzZW50LlxuICAgKi9cbiAgcXVlcnlEYXRhUGF5bG9hZCgpIHtcbiAgICBpZiAodGhpcy5fcXVlcnlEYXRhLmxlbmd0aCA9PT0gMCkgcmV0dXJuIHt9XG5cbiAgICAvLyBTaW5nbGUgYWNjdW11bGF0ZWQgc3BlYyBnb2VzIG9uIHRoZSB3aXJlIHZlcmJhdGltLiBUaGUgYmFja2VuZFxuICAgIC8vIG5vcm1hbGl6ZXIgYWNjZXB0cyBzdHJpbmcvYXJyYXkvb2JqZWN0IGF0IGVhY2ggbGV2ZWwsIHNvIHdlIGNhblxuICAgIC8vIHNoaXAgbXVsdGlwbGUgYC5xdWVyeURhdGEoLi4uKWAgY2FsbHMgYXMgYW4gYXJyYXkuXG4gICAgcmV0dXJuIHtcbiAgICAgIHF1ZXJ5RGF0YTogdGhpcy5fcXVlcnlEYXRhLmxlbmd0aCA9PT0gMSA/IHRoaXMuX3F1ZXJ5RGF0YVswXSA6IHRoaXMuX3F1ZXJ5RGF0YVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHNlbGVjdCBwYXlsb2FkLlxuICAgKiBAcGFyYW0ge3N0cmluZ1tdfSBbcmVxdWlyZWRBdHRyaWJ1dGVzXSAtIEV4dHJhIHJlcXVpcmVkIGF0dHJpYnV0ZXMgZm9yIHJvb3QgbW9kZWwgc2VsZWN0aW9uLlxuICAgKiBAcmV0dXJucyB7UmVjb3JkPHN0cmluZywgPz59IC0gUGF5bG9hZCBzZWxlY3QgaGFzaCB3aGVuIHByZXNlbnQuXG4gICAqL1xuICBzZWxlY3RQYXlsb2FkKHJlcXVpcmVkQXR0cmlidXRlcyA9IFtdKSB7XG4gICAgY29uc3Qgc2VsZWN0ID0gdGhpcy5zZWxlY3RXaXRoUmVxdWlyZWRSb290QXR0cmlidXRlcyhyZXF1aXJlZEF0dHJpYnV0ZXMpXG5cbiAgICBpZiAoT2JqZWN0LmtleXMoc2VsZWN0KS5sZW5ndGggPT09IDApIHJldHVybiB7fVxuXG4gICAgcmV0dXJuIHtzZWxlY3R9XG4gIH1cblxuICAvKipcbiAgICogUnVucyBzZWxlY3RzIGV4dHJhIHBheWxvYWQuXG4gICAqIEByZXR1cm5zIHtSZWNvcmQ8c3RyaW5nLCA/Pn0gLSBQYXlsb2FkIHNlbGVjdHNFeHRyYSBoYXNoIHdoZW4gcHJlc2VudC5cbiAgICovXG4gIHNlbGVjdHNFeHRyYVBheWxvYWQoKSB7XG4gICAgaWYgKE9iamVjdC5rZXlzKHRoaXMuX3NlbGVjdHNFeHRyYSkubGVuZ3RoID09PSAwKSByZXR1cm4ge31cblxuICAgIHJldHVybiB7c2VsZWN0c0V4dHJhOiB0aGlzLl9zZWxlY3RzRXh0cmF9XG4gIH1cblxuICAvKipcbiAgICogUnVucyBzZWFyY2ggcGF5bG9hZC5cbiAgICogQHJldHVybnMge1JlY29yZDxzdHJpbmcsID8+fSAtIFBheWxvYWQgc2VhcmNoZXMgYXJyYXkgd2hlbiBwcmVzZW50LlxuICAgKi9cbiAgc2VhcmNoUGF5bG9hZCgpIHtcbiAgICBpZiAodGhpcy5fc2VhcmNoZXMubGVuZ3RoID09PSAwKSByZXR1cm4ge31cblxuICAgIHJldHVybiB7XG4gICAgICBzZWFyY2hlczogdGhpcy5fc2VhcmNoZXMubWFwKChzZWFyY2gpID0+ICh7XG4gICAgICAgIGNvbHVtbjogc2VhcmNoLmNvbHVtbixcbiAgICAgICAgb3BlcmF0b3I6IHNlYXJjaC5vcGVyYXRvcixcbiAgICAgICAgcGF0aDogWy4uLnNlYXJjaC5wYXRoXSxcbiAgICAgICAgdmFsdWU6IHNlYXJjaC52YWx1ZVxuICAgICAgfSkpXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgcmFuc2FjayBwYXlsb2FkLlxuICAgKiBAcmV0dXJucyB7UmVjb3JkPHN0cmluZywgPz59IC0gUGF5bG9hZCByYW5zYWNrIGhhc2ggd2hlbiBwcmVzZW50LlxuICAgKi9cbiAgcmFuc2Fja1BheWxvYWQoKSB7XG4gICAgaWYgKHRoaXMuX3JhbnNhY2subGVuZ3RoID09PSAwKSByZXR1cm4ge31cblxuICAgIGlmICh0aGlzLl9yYW5zYWNrLmxlbmd0aCA9PT0gMSkge1xuICAgICAgcmV0dXJuIHtyYW5zYWNrOiB0aGlzLl9yYW5zYWNrWzBdfVxuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICByYW5zYWNrOiB7XG4gICAgICAgIGc6IHRoaXMuX3JhbnNhY2ssXG4gICAgICAgIG06IFwiYW5kXCJcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUnVucyBqb2lucyBwYXlsb2FkLlxuICAgKiBAcmV0dXJucyB7UmVjb3JkPHN0cmluZywgPz59IC0gUGF5bG9hZCBqb2lucyBoYXNoIHdoZW4gcHJlc2VudC5cbiAgICovXG4gIGpvaW5zUGF5bG9hZCgpIHtcbiAgICBpZiAoT2JqZWN0LmtleXModGhpcy5fam9pbnMpLmxlbmd0aCA9PT0gMCkgcmV0dXJuIHt9XG5cbiAgICByZXR1cm4ge1xuICAgICAgam9pbnM6IG5vcm1hbGl6ZUpvaW5zKHRoaXMuX2pvaW5zKVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHNvcnQgcGF5bG9hZC5cbiAgICogQHJldHVybnMge1JlY29yZDxzdHJpbmcsID8+fSAtIFBheWxvYWQgc29ydCBhcnJheSB3aGVuIHByZXNlbnQuXG4gICAqL1xuICBzb3J0UGF5bG9hZCgpIHtcbiAgICBpZiAodGhpcy5fc29ydC5sZW5ndGggPT09IDApIHJldHVybiB7fVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIHNvcnQ6IHRoaXMuX3NvcnQubWFwKChzb3J0RW50cnkpID0+ICh7XG4gICAgICAgIGNvbHVtbjogc29ydEVudHJ5LmNvbHVtbixcbiAgICAgICAgZGlyZWN0aW9uOiBzb3J0RW50cnkuZGlyZWN0aW9uLFxuICAgICAgICBwYXRoOiBbLi4uc29ydEVudHJ5LnBhdGhdXG4gICAgICB9KSlcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUnVucyBncm91cCBwYXlsb2FkLlxuICAgKiBAcmV0dXJucyB7UmVjb3JkPHN0cmluZywgPz59IC0gUGF5bG9hZCBncm91cCBhcnJheSB3aGVuIHByZXNlbnQuXG4gICAqL1xuICBncm91cFBheWxvYWQoKSB7XG4gICAgaWYgKHRoaXMuX2dyb3VwLmxlbmd0aCA9PT0gMCkgcmV0dXJuIHt9XG5cbiAgICByZXR1cm4ge1xuICAgICAgZ3JvdXA6IHRoaXMuX2dyb3VwLm1hcCgoZ3JvdXBFbnRyeSkgPT4gKHtcbiAgICAgICAgY29sdW1uOiBncm91cEVudHJ5LmNvbHVtbixcbiAgICAgICAgcGF0aDogWy4uLmdyb3VwRW50cnkucGF0aF1cbiAgICAgIH0pKVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGRpc3RpbmN0IHBheWxvYWQuXG4gICAqIEByZXR1cm5zIHtSZWNvcmQ8c3RyaW5nLCA/Pn0gLSBQYXlsb2FkIGRpc3RpbmN0IGZsYWcgd2hlbiBlbmFibGVkLlxuICAgKi9cbiAgZGlzdGluY3RQYXlsb2FkKCkge1xuICAgIGlmICghdGhpcy5fZGlzdGluY3QpIHJldHVybiB7fVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGRpc3RpbmN0OiB0cnVlXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgd2hlcmUgcGF5bG9hZC5cbiAgICogQHJldHVybnMge1JlY29yZDxzdHJpbmcsID8+fSAtIFBheWxvYWQgd2hlcmUgaGFzaCB3aGVuIHByZXNlbnQuXG4gICAqL1xuICB3aGVyZVBheWxvYWQoKSB7XG4gICAgaWYgKE9iamVjdC5rZXlzKHRoaXMuX3doZXJlKS5sZW5ndGggPT09IDApIHJldHVybiB7fVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIHdoZXJlOiB0aGlzLl93aGVyZVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHBhZ2luYXRpb24gcGF5bG9hZC5cbiAgICogQHJldHVybnMge1JlY29yZDxzdHJpbmcsID8+fSAtIFBheWxvYWQgcGFnaW5hdGlvbiBwYXJhbXMgd2hlbiBwcmVzZW50LlxuICAgKi9cbiAgcGFnaW5hdGlvblBheWxvYWQoKSB7XG4gICAgLyoqXG4gICAgICogUGF5bG9hZC5cbiAgICAgIEB0eXBlIHtSZWNvcmQ8c3RyaW5nLCA/Pn0gKi9cbiAgICBjb25zdCBwYXlsb2FkID0ge31cblxuICAgIGlmICh0aGlzLl9saW1pdCAhPT0gbnVsbCkgcGF5bG9hZC5saW1pdCA9IHRoaXMuX2xpbWl0XG4gICAgaWYgKHRoaXMuX29mZnNldCAhPT0gbnVsbCkgcGF5bG9hZC5vZmZzZXQgPSB0aGlzLl9vZmZzZXRcbiAgICBpZiAodGhpcy5fcGFnZSAhPT0gbnVsbCkgcGF5bG9hZC5wYWdlID0gdGhpcy5fcGFnZVxuICAgIGlmICh0aGlzLl9wZXJQYWdlICE9PSBudWxsKSBwYXlsb2FkLnBlclBhZ2UgPSB0aGlzLl9wZXJQYWdlXG5cbiAgICByZXR1cm4gcGF5bG9hZFxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgYXNzZXJ0IGV2ZW50IHF1ZXJ5IHN1cHBvcnRlZC5cbiAgICogQHJldHVybnMge3ZvaWR9XG4gICAqIEB0aHJvd3Mge0Vycm9yfSBXaGVuIHRoZSBxdWVyeSBjb250YWlucyBsaXN0LW9ubHkgb3B0aW9ucyB0aGF0IGNhbm5vdCBmaWx0ZXIgYSBzaW5nbGUgbGlmZWN5Y2xlIGV2ZW50LlxuICAgKi9cbiAgYXNzZXJ0RXZlbnRRdWVyeVN1cHBvcnRlZCgpIHtcbiAgICAvKipcbiAgICAgKiBVbnN1cHBvcnRlZCBvcHRpb25zLlxuICAgICAgQHR5cGUge3N0cmluZ1tdfSAqL1xuICAgIGNvbnN0IHVuc3VwcG9ydGVkT3B0aW9ucyA9IFtdXG5cbiAgICBpZiAodGhpcy5fc29ydC5sZW5ndGggPiAwKSB1bnN1cHBvcnRlZE9wdGlvbnMucHVzaChcInNvcnRcIilcbiAgICBpZiAodGhpcy5fZ3JvdXAubGVuZ3RoID4gMCkgdW5zdXBwb3J0ZWRPcHRpb25zLnB1c2goXCJncm91cFwiKVxuICAgIGlmICh0aGlzLl9kaXN0aW5jdCkgdW5zdXBwb3J0ZWRPcHRpb25zLnB1c2goXCJkaXN0aW5jdFwiKVxuICAgIGlmICh0aGlzLl9yYW5zYWNrLmxlbmd0aCA+IDApIHVuc3VwcG9ydGVkT3B0aW9ucy5wdXNoKFwicmFuc2Fja1wiKVxuICAgIGlmICh0aGlzLl9saW1pdCAhPT0gbnVsbCB8fCB0aGlzLl9vZmZzZXQgIT09IG51bGwgfHwgdGhpcy5fcGFnZSAhPT0gbnVsbCB8fCB0aGlzLl9wZXJQYWdlICE9PSBudWxsKSB1bnN1cHBvcnRlZE9wdGlvbnMucHVzaChcInBhZ2luYXRpb25cIilcblxuICAgIGlmICh1bnN1cHBvcnRlZE9wdGlvbnMubGVuZ3RoID09PSAwKSByZXR1cm5cblxuICAgIHRocm93IG5ldyBFcnJvcihgRnJvbnRlbmQgbW9kZWwgZXZlbnQgcXVlcmllcyBkbyBub3Qgc3VwcG9ydCAke3Vuc3VwcG9ydGVkT3B0aW9ucy5qb2luKFwiLCBcIil9YClcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGV2ZW50IHByb2plY3Rpb24gcGF5bG9hZC5cbiAgICogQHJldHVybnMge0Zyb250ZW5kTW9kZWxQcm9qZWN0aW9uUGF5bG9hZH0gLSBQcm9qZWN0aW9uIHBheWxvYWQgdXNlZCB3aGVuIHNlcmlhbGl6aW5nIGxpZmVjeWNsZSBldmVudHMuXG4gICAqL1xuICBldmVudFByb2plY3Rpb25QYXlsb2FkKCkge1xuICAgIHRoaXMuYXNzZXJ0RXZlbnRRdWVyeVN1cHBvcnRlZCgpXG5cbiAgICByZXR1cm4ge1xuICAgICAgLi4udGhpcy5wcmVsb2FkUGF5bG9hZCgpLFxuICAgICAgLi4udGhpcy5zZWxlY3RQYXlsb2FkKCksXG4gICAgICAuLi50aGlzLnNlbGVjdHNFeHRyYVBheWxvYWQoKSxcbiAgICAgIC4uLnRoaXMud2l0aENvdW50UGF5bG9hZCgpLFxuICAgICAgLi4udGhpcy5hYmlsaXRpZXNQYXlsb2FkKCksXG4gICAgICAuLi50aGlzLnF1ZXJ5RGF0YVBheWxvYWQoKVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGV2ZW50IGZpbHRlciBwYXlsb2FkLlxuICAgKiBAcmV0dXJucyB7RnJvbnRlbmRNb2RlbEV2ZW50RmlsdGVyUGF5bG9hZCB8IG51bGx9IC0gUXVlcnkgcGllY2VzIHVzZWQgdG8gbWF0Y2ggbGlmZWN5Y2xlIGV2ZW50cy5cbiAgICovXG4gIGV2ZW50RmlsdGVyUGF5bG9hZCgpIHtcbiAgICB0aGlzLmFzc2VydEV2ZW50UXVlcnlTdXBwb3J0ZWQoKVxuXG4gICAgY29uc3QgcGF5bG9hZCA9IHtcbiAgICAgIC4uLnRoaXMuam9pbnNQYXlsb2FkKCksXG4gICAgICAuLi50aGlzLnNlYXJjaFBheWxvYWQoKSxcbiAgICAgIC4uLnRoaXMud2hlcmVQYXlsb2FkKClcbiAgICB9XG5cbiAgICByZXR1cm4gT2JqZWN0LmtleXMocGF5bG9hZCkubGVuZ3RoID09PSAwID8gbnVsbCA6IHBheWxvYWRcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBldmVudE9wdGlvbnNQYXlsb2FkIHJlc3VsdC5cbiAgICogQHJldHVybnMge0Zyb250ZW5kTW9kZWxFdmVudE9wdGlvbnNQYXlsb2FkfSAtIENvbWJpbmVkIGV2ZW50IGZpbHRlciBhbmQgcHJvamVjdGlvbiBwYXlsb2FkLlxuICAgKi9cbiAgZXZlbnRPcHRpb25zUGF5bG9hZCgpIHtcbiAgICBjb25zdCBldmVudEZpbHRlclBheWxvYWQgPSB0aGlzLmV2ZW50RmlsdGVyUGF5bG9hZCgpXG5cbiAgICByZXR1cm4ge1xuICAgICAgZXZlbnRGaWx0ZXJLZXk6IGV2ZW50RmlsdGVyUGF5bG9hZCA/IGZyb250ZW5kTW9kZWxFdmVudEZpbHRlcktleShldmVudEZpbHRlclBheWxvYWQpIDogbnVsbCxcbiAgICAgIGV2ZW50RmlsdGVyUGF5bG9hZCxcbiAgICAgIHByb2plY3Rpb25QYXlsb2FkOiB0aGlzLmV2ZW50UHJvamVjdGlvblBheWxvYWQoKVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGxvYWQuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPEluc3RhbmNlVHlwZTxUPltdPn0gLSBMb2FkZWQgbW9kZWwgaW5zdGFuY2VzLlxuICAgKi9cbiAgYXN5bmMgbG9hZCgpIHtcbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMubW9kZWxDbGFzcy5leGVjdXRlQ29tbWFuZChcImluZGV4XCIsIHtcbiAgICAgIC4uLnRoaXMucHJlbG9hZFBheWxvYWQoKSxcbiAgICAgIC4uLnRoaXMuam9pbnNQYXlsb2FkKCksXG4gICAgICAuLi50aGlzLnJhbnNhY2tQYXlsb2FkKCksXG4gICAgICAuLi50aGlzLnNlYXJjaFBheWxvYWQoKSxcbiAgICAgIC4uLnRoaXMuc2VsZWN0UGF5bG9hZCgpLFxuICAgICAgLi4udGhpcy5zZWxlY3RzRXh0cmFQYXlsb2FkKCksXG4gICAgICAuLi50aGlzLmdyb3VwUGF5bG9hZCgpLFxuICAgICAgLi4udGhpcy5kaXN0aW5jdFBheWxvYWQoKSxcbiAgICAgIC4uLnRoaXMuc29ydFBheWxvYWQoKSxcbiAgICAgIC4uLnRoaXMud2hlcmVQYXlsb2FkKCksXG4gICAgICAuLi50aGlzLndpdGhDb3VudFBheWxvYWQoKSxcbiAgICAgIC4uLnRoaXMuYWJpbGl0aWVzUGF5bG9hZCgpLFxuICAgICAgLi4udGhpcy5xdWVyeURhdGFQYXlsb2FkKCksXG4gICAgICAuLi50aGlzLnBhZ2luYXRpb25QYXlsb2FkKClcbiAgICB9KVxuXG4gICAgaWYgKCFyZXNwb25zZSB8fCB0eXBlb2YgcmVzcG9uc2UgIT09IFwib2JqZWN0XCIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQgb2JqZWN0IHJlc3BvbnNlIGJ1dCBnb3Q6ICR7cmVzcG9uc2V9YClcbiAgICB9XG5cbiAgICBjb25zdCBtb2RlbHNEYXRhID0gQXJyYXkuaXNBcnJheShyZXNwb25zZS5tb2RlbHMpID8gcmVzcG9uc2UubW9kZWxzIDogW11cbiAgICAvKipcbiAgICAgKiBNb2RlbHMuXG4gICAgICBAdHlwZSB7SW5zdGFuY2VUeXBlPFQ+W119ICovXG4gICAgY29uc3QgbW9kZWxzID0gbW9kZWxzRGF0YS5tYXAoKG1vZGVsKSA9PiB0aGlzLm1vZGVsQ2xhc3MuaW5zdGFudGlhdGVGcm9tUmVzcG9uc2UobW9kZWwpKVxuXG4gICAgLy8gU2hhcmUgYSBzaW5nbGUgY29ob3J0IHJlZmVyZW5jZSBhY3Jvc3MgZXZlcnkgc2libGluZyBzbyBhdXRvLWJhdGNoLXByZWxvYWRcbiAgICAvLyBjYW4gYmF0Y2ggbGF6eSByZWxhdGlvbnNoaXAgYWNjZXNzIGxhdGVyLiBTaW5nbGUtcmVjb3JkIGxvb2t1cHMgc3RpbGwgZmxvd1xuICAgIC8vIHRocm91Z2ggaGVyZSAod2l0aCBhIGNvaG9ydCBvZiBvbmUpIGFuZCBkZWdyYWRlIGNsZWFubHkgdG8gcGVyLXJlY29yZCBsb2FkLlxuICAgIGZvciAoY29uc3QgbW9kZWwgb2YgbW9kZWxzKSB7XG4gICAgICAvKipcbiAgICAgICAqIE5hcnJvd3MgdGhlIHJ1bnRpbWUgdmFsdWUgdG8gdGhlIGRvY3VtZW50ZWQgdHlwZS5cbiAgICAgICAgQHR5cGUgez99ICovIChtb2RlbCkuX2xvYWRDb2hvcnQgPSBtb2RlbHNcbiAgICB9XG5cbiAgICByZXR1cm4gbW9kZWxzXG4gIH1cblxuICAvKipcbiAgICogUnVucyB0byBhcnJheS5cbiAgICogQHJldHVybnMge1Byb21pc2U8SW5zdGFuY2VUeXBlPFQ+W10+fSAtIExvYWRlZCBtb2RlbCBpbnN0YW5jZXMuXG4gICAqL1xuICBhc3luYyB0b0FycmF5KCkge1xuICAgIHJldHVybiBhd2FpdCB0aGlzLmxvYWQoKVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgY291bnQuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPG51bWJlcj59IC0gTnVtYmVyIG9mIGxvYWRlZCBtb2RlbCBpbnN0YW5jZXMuXG4gICAqL1xuICBhc3luYyBjb3VudCgpIHtcbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMubW9kZWxDbGFzcy5leGVjdXRlQ29tbWFuZChcImluZGV4XCIsIHtcbiAgICAgIC4uLnRoaXMuam9pbnNQYXlsb2FkKCksXG4gICAgICAuLi50aGlzLnJhbnNhY2tQYXlsb2FkKCksXG4gICAgICAuLi50aGlzLnNlYXJjaFBheWxvYWQoKSxcbiAgICAgIC4uLnRoaXMuZ3JvdXBQYXlsb2FkKCksXG4gICAgICAuLi50aGlzLmRpc3RpbmN0UGF5bG9hZCgpLFxuICAgICAgLi4udGhpcy53aGVyZVBheWxvYWQoKSxcbiAgICAgIC4uLnRoaXMucGFnaW5hdGlvblBheWxvYWQoKSxcbiAgICAgIGNvdW50OiB0cnVlXG4gICAgfSlcblxuICAgIGlmICghcmVzcG9uc2UgfHwgdHlwZW9mIHJlc3BvbnNlICE9PSBcIm9iamVjdFwiKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEV4cGVjdGVkIG9iamVjdCByZXNwb25zZSBidXQgZ290OiAke3Jlc3BvbnNlfWApXG4gICAgfVxuXG4gICAgaWYgKCFOdW1iZXIuaXNGaW5pdGUocmVzcG9uc2UuY291bnQpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEV4cGVjdGVkIG51bWVyaWMgY291bnQgcmVzcG9uc2UgYnV0IGdvdDogJHtyZXNwb25zZS5jb3VudH1gKVxuICAgIH1cblxuICAgIHJldHVybiByZXNwb25zZS5jb3VudFxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgZmlyc3QuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPEluc3RhbmNlVHlwZTxUPiB8IG51bGw+fSAtIEZpcnN0IG1vZGVsIG1hdGNoaW5nIHF1ZXJ5LlxuICAgKi9cbiAgYXN5bmMgZmlyc3QoKSB7XG4gICAgY29uc3QgcXVlcnkgPSB0aGlzLmNsb25lKClcblxuICAgIGlmIChxdWVyeS5fc29ydC5sZW5ndGggPCAxKSB7XG4gICAgICBxdWVyeS5zb3J0KFtbdGhpcy5tb2RlbENsYXNzLnByaW1hcnlLZXkoKSwgXCJhc2NcIl1dKVxuICAgIH1cblxuICAgIHF1ZXJ5LmxpbWl0KDEpXG5cbiAgICBjb25zdCBtb2RlbHMgPSBhd2FpdCBxdWVyeS50b0FycmF5KClcblxuICAgIHJldHVybiBtb2RlbHNbMF0gfHwgbnVsbFxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgbGFzdC5cbiAgICogQHJldHVybnMge1Byb21pc2U8SW5zdGFuY2VUeXBlPFQ+IHwgbnVsbD59IC0gTGFzdCBtb2RlbCBtYXRjaGluZyBxdWVyeS5cbiAgICovXG4gIGFzeW5jIGxhc3QoKSB7XG4gICAgLy8gV2hlbiBwYWdpbmF0aW9uIGlzIGFscmVhZHkgYXBwbGllZCwgZmV0Y2ggdGhhdCBzY29wZWQgd2luZG93IGFuZCByZXR1cm4gaXRzIGxhc3QgaXRlbS5cbiAgICBpZiAodGhpcy5fb2Zmc2V0ICE9PSBudWxsIHx8IHRoaXMuX3BhZ2UgIT09IG51bGwgfHwgdGhpcy5fcGVyUGFnZSAhPT0gbnVsbCkge1xuICAgICAgY29uc3QgbW9kZWxzID0gYXdhaXQgdGhpcy50b0FycmF5KClcblxuICAgICAgaWYgKG1vZGVscy5sZW5ndGggPCAxKSByZXR1cm4gbnVsbFxuXG4gICAgICByZXR1cm4gbW9kZWxzW21vZGVscy5sZW5ndGggLSAxXVxuICAgIH1cblxuICAgIGNvbnN0IHF1ZXJ5ID0gdGhpcy5jbG9uZSgpXG5cbiAgICBpZiAocXVlcnkuX3NvcnQubGVuZ3RoIDwgMSkge1xuICAgICAgcXVlcnkuc29ydChbW3RoaXMubW9kZWxDbGFzcy5wcmltYXJ5S2V5KCksIFwiZGVzY1wiXV0pXG4gICAgfSBlbHNlIHtcbiAgICAgIHF1ZXJ5Ll9zb3J0ID0gcXVlcnkuX3NvcnQubWFwKChzb3J0RW50cnkpID0+ICh7XG4gICAgICAgIC4uLnNvcnRFbnRyeSxcbiAgICAgICAgZGlyZWN0aW9uOiByZXZlcnNlU29ydERpcmVjdGlvbihzb3J0RW50cnkuZGlyZWN0aW9uKVxuICAgICAgfSkpXG4gICAgfVxuXG4gICAgcXVlcnkubGltaXQoMSlcblxuICAgIGNvbnN0IG1vZGVscyA9IGF3YWl0IHF1ZXJ5LnRvQXJyYXkoKVxuXG4gICAgcmV0dXJuIG1vZGVsc1swXSB8fCBudWxsXG4gIH1cblxuICAvKipcbiAgICogUnVucyBwbHVjay5cbiAgICogQHBhcmFtIHsuLi4oc3RyaW5nIHwgc3RyaW5nW10gfCBSZWNvcmQ8c3RyaW5nLCA/PiB8IEFycmF5PFJlY29yZDxzdHJpbmcsID8+Pil9IGNvbHVtbnMgLSBQbHVjayBkZWZpbml0aW9uKHMpLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxBcnJheTw/Pj59IC0gUGx1Y2tlZCB2YWx1ZXMuXG4gICAqL1xuICBhc3luYyBwbHVjayguLi5jb2x1bW5zKSB7XG4gICAgaWYgKGNvbHVtbnMubGVuZ3RoIDwgMSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTm8gY29sdW1ucyBnaXZlbiB0byBwbHVja1wiKVxuICAgIH1cblxuICAgIGNvbnN0IG5vcm1hbGl6ZWRQbHVjayA9IG5vcm1hbGl6ZVBsdWNrKGNvbHVtbnMubGVuZ3RoID09PSAxID8gY29sdW1uc1swXSA6IGNvbHVtbnMpXG4gICAgY29uc3QgdmFsaWRhdGVkUGx1Y2sgPSB2YWxpZGF0ZVBsdWNrRGVmaW5pdGlvbnMoe1xuICAgICAgbW9kZWxDbGFzczogdGhpcy5tb2RlbENsYXNzLFxuICAgICAgcGx1Y2s6IG5vcm1hbGl6ZWRQbHVja1xuICAgIH0pXG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCB0aGlzLm1vZGVsQ2xhc3MuZXhlY3V0ZUNvbW1hbmQoXCJpbmRleFwiLCB7XG4gICAgICAuLi50aGlzLmpvaW5zUGF5bG9hZCgpLFxuICAgICAgLi4udGhpcy5zZWFyY2hQYXlsb2FkKCksXG4gICAgICAuLi50aGlzLmdyb3VwUGF5bG9hZCgpLFxuICAgICAgLi4udGhpcy5kaXN0aW5jdFBheWxvYWQoKSxcbiAgICAgIC4uLnRoaXMuc29ydFBheWxvYWQoKSxcbiAgICAgIC4uLnRoaXMud2hlcmVQYXlsb2FkKCksXG4gICAgICAuLi50aGlzLnBhZ2luYXRpb25QYXlsb2FkKCksXG4gICAgICBwbHVjazogdmFsaWRhdGVkUGx1Y2tcbiAgICB9KVxuXG4gICAgaWYgKCFyZXNwb25zZSB8fCB0eXBlb2YgcmVzcG9uc2UgIT09IFwib2JqZWN0XCIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQgb2JqZWN0IHJlc3BvbnNlIGJ1dCBnb3Q6ICR7cmVzcG9uc2V9YClcbiAgICB9XG5cbiAgICBpZiAoIUFycmF5LmlzQXJyYXkocmVzcG9uc2UudmFsdWVzKSkge1xuICAgICAgcmV0dXJuIFtdXG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3BvbnNlLnZhbHVlc1xuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgZmluZC5cbiAgICogQHBhcmFtIHtudW1iZXIgfCBzdHJpbmd9IGlkIC0gUmVjb3JkIGlkLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxJbnN0YW5jZVR5cGU8VD4+fSAtIEZvdW5kIG1vZGVsLlxuICAgKi9cbiAgYXN5bmMgZmluZChpZCkge1xuICAgIGNvbnN0IHBrID0gdGhpcy5tb2RlbENsYXNzLnByaW1hcnlLZXkoKVxuICAgIGNvbnN0IG1vZGVsID0gYXdhaXQgdGhpcy5maW5kQnkoe1twa106IGlkfSlcblxuICAgIGlmICghbW9kZWwpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgJHt0aGlzLm1vZGVsQ2xhc3MuZ2V0TW9kZWxOYW1lKCl9IG5vdCBmb3VuZCB3aXRoICR7cGt9PSR7aWR9YClcbiAgICB9XG5cbiAgICByZXR1cm4gbW9kZWxcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGZpbmQgYnkuXG4gICAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgPz59IGNvbmRpdGlvbnMgLSBDb25kaXRpb25zLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxJbnN0YW5jZVR5cGU8VD4gfCBudWxsPn0gLSBGb3VuZCBtb2RlbCBvciBudWxsLlxuICAgKi9cbiAgYXN5bmMgZmluZEJ5KGNvbmRpdGlvbnMpIHtcbiAgICBjb25zdCBub3JtYWxpemVkQ29uZGl0aW9ucyA9IHRoaXMudmFsaWRhdGVkU3RydWN0dXJlZENvbmRpdGlvbnMoY29uZGl0aW9ucylcbiAgICBjb25zdCBtZXJnZWRXaGVyZSA9IHtcbiAgICAgIC4uLnRoaXMuX3doZXJlLFxuICAgICAgLi4ubm9ybWFsaXplZENvbmRpdGlvbnNcbiAgICB9XG5cbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMubW9kZWxDbGFzcy5leGVjdXRlQ29tbWFuZChcImluZGV4XCIsIHtcbiAgICAgIC4uLnRoaXMucHJlbG9hZFBheWxvYWQoKSxcbiAgICAgIC4uLnRoaXMuam9pbnNQYXlsb2FkKCksXG4gICAgICAuLi50aGlzLnNlYXJjaFBheWxvYWQoKSxcbiAgICAgIC4uLnRoaXMuc2VsZWN0UGF5bG9hZChPYmplY3Qua2V5cyhtZXJnZWRXaGVyZSkpLFxuICAgICAgLi4udGhpcy5zZWxlY3RzRXh0cmFQYXlsb2FkKCksXG4gICAgICAuLi50aGlzLmdyb3VwUGF5bG9hZCgpLFxuICAgICAgLi4udGhpcy5kaXN0aW5jdFBheWxvYWQoKSxcbiAgICAgIC4uLnRoaXMuc29ydFBheWxvYWQoKSxcbiAgICAgIC4uLnRoaXMuYWJpbGl0aWVzUGF5bG9hZCgpLFxuICAgICAgLi4udGhpcy5wYWdpbmF0aW9uUGF5bG9hZCgpLFxuICAgICAgd2hlcmU6IG1lcmdlZFdoZXJlXG4gICAgfSlcblxuICAgIGlmICghcmVzcG9uc2UgfHwgdHlwZW9mIHJlc3BvbnNlICE9PSBcIm9iamVjdFwiKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEV4cGVjdGVkIG9iamVjdCByZXNwb25zZSBidXQgZ290OiAke3Jlc3BvbnNlfWApXG4gICAgfVxuXG4gICAgY29uc3QgbW9kZWxzID0gQXJyYXkuaXNBcnJheShyZXNwb25zZS5tb2RlbHMpID8gcmVzcG9uc2UubW9kZWxzIDogW11cblxuICAgIGZvciAoY29uc3QgbW9kZWxEYXRhIG9mIG1vZGVscykge1xuICAgICAgY29uc3QgbW9kZWwgPSB0aGlzLm1vZGVsQ2xhc3MuaW5zdGFudGlhdGVGcm9tUmVzcG9uc2UobW9kZWxEYXRhKVxuXG4gICAgICBpZiAodGhpcy5tb2RlbENsYXNzLm1hdGNoZXNGaW5kQnlDb25kaXRpb25zKG1vZGVsLCBtZXJnZWRXaGVyZSkpIHtcbiAgICAgICAgcmV0dXJuIG1vZGVsXG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIG51bGxcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGZpbmQgYnkgb3IgZmFpbC5cbiAgICogQHBhcmFtIHtSZWNvcmQ8c3RyaW5nLCA/Pn0gY29uZGl0aW9ucyAtIENvbmRpdGlvbnMuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPEluc3RhbmNlVHlwZTxUPj59IC0gRm91bmQgbW9kZWwuXG4gICAqL1xuICBhc3luYyBmaW5kQnlPckZhaWwoY29uZGl0aW9ucykge1xuICAgIGNvbnN0IG1vZGVsID0gYXdhaXQgdGhpcy5maW5kQnkoY29uZGl0aW9ucylcblxuICAgIGlmICghbW9kZWwpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgJHt0aGlzLm1vZGVsQ2xhc3MubmFtZX0gbm90IGZvdW5kIGZvciBjb25kaXRpb25zOiAke3NlcmlhbGl6ZUZpbmRDb25kaXRpb25zKGNvbmRpdGlvbnMpfWApXG4gICAgfVxuXG4gICAgcmV0dXJuIG1vZGVsXG4gIH1cblxuICAvKipcbiAgICogUnVucyBmaW5kIG9yIGluaXRpYWxpemUgYnkuXG4gICAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgPz59IGNvbmRpdGlvbnMgLSBDb25kaXRpb25zLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxJbnN0YW5jZVR5cGU8VD4+fSAtIEV4aXN0aW5nIG9yIGluaXRpYWxpemVkIG1vZGVsLlxuICAgKi9cbiAgYXN5bmMgZmluZE9ySW5pdGlhbGl6ZUJ5KGNvbmRpdGlvbnMpIHtcbiAgICBjb25zdCBub3JtYWxpemVkQ29uZGl0aW9ucyA9IHRoaXMudmFsaWRhdGVkU3RydWN0dXJlZENvbmRpdGlvbnMoY29uZGl0aW9ucylcbiAgICBjb25zdCBtb2RlbCA9IGF3YWl0IHRoaXMuZmluZEJ5KGNvbmRpdGlvbnMpXG5cbiAgICBpZiAobW9kZWwpIHJldHVybiBtb2RlbFxuXG4gICAgcmV0dXJuIC8qKiBOYXJyb3dzIHRoZSBydW50aW1lIHZhbHVlIHRvIHRoZSBkb2N1bWVudGVkIHR5cGUuIEB0eXBlIHtJbnN0YW5jZVR5cGU8VD59ICovIChuZXcgdGhpcy5tb2RlbENsYXNzKG5vcm1hbGl6ZWRDb25kaXRpb25zKSlcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGZpbmQgb3IgY3JlYXRlIGJ5LlxuICAgKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsID8+fSBjb25kaXRpb25zIC0gQ29uZGl0aW9ucy5cbiAgICogQHBhcmFtIHsobW9kZWw6IEluc3RhbmNlVHlwZTxUPikgPT4gUHJvbWlzZTx2b2lkPiB8IHZvaWR9IFtjYWxsYmFja10gLSBPcHRpb25hbCBjYWxsYmFjayBiZWZvcmUgc2F2ZS5cbiAgICogQHJldHVybnMge1Byb21pc2U8SW5zdGFuY2VUeXBlPFQ+Pn0gLSBFeGlzdGluZyBvciBuZXdseSBjcmVhdGVkIG1vZGVsLlxuICAgKi9cbiAgYXN5bmMgZmluZE9yQ3JlYXRlQnkoY29uZGl0aW9ucywgY2FsbGJhY2spIHtcbiAgICBjb25zdCBub3JtYWxpemVkQ29uZGl0aW9ucyA9IHRoaXMudmFsaWRhdGVkU3RydWN0dXJlZENvbmRpdGlvbnMoY29uZGl0aW9ucylcbiAgICBjb25zdCBtb2RlbCA9IGF3YWl0IHRoaXMuZmluZEJ5KGNvbmRpdGlvbnMpXG5cbiAgICBpZiAobW9kZWwpIHJldHVybiBtb2RlbFxuXG4gICAgY29uc3QgbmV3TW9kZWwgPSAvKipcbiAgICAgICAgICAgICAgICAgICAgICAqIE5hcnJvd3MgdGhlIHJ1bnRpbWUgdmFsdWUgdG8gdGhlIGRvY3VtZW50ZWQgdHlwZS5cbiAgICAgICAgICAgICAgICAgICAgICAgQHR5cGUge0luc3RhbmNlVHlwZTxUPn0gKi8gKG5ldyB0aGlzLm1vZGVsQ2xhc3Mobm9ybWFsaXplZENvbmRpdGlvbnMpKVxuXG4gICAgaWYgKGNhbGxiYWNrKSB7XG4gICAgICBhd2FpdCBjYWxsYmFjayhuZXdNb2RlbClcbiAgICB9XG5cbiAgICBhd2FpdCBuZXdNb2RlbC5zYXZlKClcblxuICAgIHJldHVybiBuZXdNb2RlbFxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgdmFsaWRhdGVkIHN0cnVjdHVyZWQgY29uZGl0aW9ucy5cbiAgICogQHBhcmFtIHtSZWNvcmQ8c3RyaW5nLCA/Pn0gY29uZGl0aW9ucyAtIENhbmRpZGF0ZSBzdHJ1Y3R1cmVkIGNvbmRpdGlvbnMuXG4gICAqIEByZXR1cm5zIHtSZWNvcmQ8c3RyaW5nLCA/Pn0gLSBWYWxpZGF0ZWQgY29uZGl0aW9ucy5cbiAgICovXG4gIHZhbGlkYXRlZFN0cnVjdHVyZWRDb25kaXRpb25zKGNvbmRpdGlvbnMpIHtcbiAgICB0aGlzLm1vZGVsQ2xhc3MuYXNzZXJ0RmluZEJ5Q29uZGl0aW9ucyhjb25kaXRpb25zKVxuXG4gICAgcmV0dXJuIGNvbmRpdGlvbnNcbiAgfVxufVxuXG4vKipcbiAqIFJ1bnMgZnJvbnRlbmQgbW9kZWwgZXZlbnQgZmlsdGVyIGtleS5cbiAqIEBwYXJhbSB7RnJvbnRlbmRNb2RlbEV2ZW50RmlsdGVyUGF5bG9hZH0gcGF5bG9hZCAtIEV2ZW50IGZpbHRlciBwYXlsb2FkLlxuICogQHJldHVybnMge3N0cmluZ30gLSBTdGFibGUga2V5IGZvciBldmVudCBmaWx0ZXIgbWF0Y2hpbmcuXG4gKi9cbmZ1bmN0aW9uIGZyb250ZW5kTW9kZWxFdmVudEZpbHRlcktleShwYXlsb2FkKSB7XG4gIHJldHVybiBKU09OLnN0cmluZ2lmeShwYXlsb2FkKVxufVxuXG4vKipcbiAqIFJ1bnMgYXBwbHkgZnJvbnRlbmQgbW9kZWwgcHJvamVjdGlvbiBvcHRpb25zLlxuICogQHBhcmFtIHtGcm9udGVuZE1vZGVsUXVlcnk8dHlwZW9mIGltcG9ydChcIi4vYmFzZS5qc1wiKS5kZWZhdWx0Pn0gcXVlcnkgLSBRdWVyeSByZWNlaXZpbmcgcHJvamVjdGlvbiBvcHRpb25zLlxuICogQHBhcmFtIHtGcm9udGVuZE1vZGVsUHJvamVjdGlvbk9wdGlvbnN9IG9wdGlvbnMgLSBQcm9qZWN0aW9uIG9wdGlvbnMuXG4gKiBAcmV0dXJucyB7dm9pZH1cbiAqL1xuZnVuY3Rpb24gYXBwbHlGcm9udGVuZE1vZGVsUHJvamVjdGlvbk9wdGlvbnMocXVlcnksIG9wdGlvbnMpIHtcbiAgaWYgKG9wdGlvbnMuc2VsZWN0ICE9PSB1bmRlZmluZWQpIHF1ZXJ5LnNlbGVjdChvcHRpb25zLnNlbGVjdClcbiAgaWYgKG9wdGlvbnMuc2VsZWN0c0V4dHJhICE9PSB1bmRlZmluZWQpIHF1ZXJ5LnNlbGVjdHNFeHRyYShvcHRpb25zLnNlbGVjdHNFeHRyYSlcbiAgaWYgKG9wdGlvbnMucHJlbG9hZCAhPT0gdW5kZWZpbmVkKSBxdWVyeS5wcmVsb2FkKG9wdGlvbnMucHJlbG9hZClcbiAgaWYgKG9wdGlvbnMud2l0aENvdW50ICE9PSB1bmRlZmluZWQpIHF1ZXJ5LndpdGhDb3VudChvcHRpb25zLndpdGhDb3VudClcbiAgaWYgKG9wdGlvbnMuYWJpbGl0aWVzICE9PSB1bmRlZmluZWQpIHF1ZXJ5LmFiaWxpdGllcyhvcHRpb25zLmFiaWxpdGllcylcbiAgaWYgKG9wdGlvbnMucXVlcnlEYXRhICE9PSB1bmRlZmluZWQpIHF1ZXJ5LnF1ZXJ5RGF0YShvcHRpb25zLnF1ZXJ5RGF0YSlcbn1cblxuLyoqXG4gKiBSdW5zIGFzc2VydCBmcm9udGVuZCBtb2RlbCBldmVudCBxdWVyeSBjbGFzcy5cbiAqIEBwYXJhbSB7dHlwZW9mIGltcG9ydChcIi4vYmFzZS5qc1wiKS5kZWZhdWx0fSBtb2RlbENsYXNzIC0gRXhwZWN0ZWQgZnJvbnRlbmQgbW9kZWwgY2xhc3MuXG4gKiBAcGFyYW0ge0Zyb250ZW5kTW9kZWxRdWVyeTx0eXBlb2YgaW1wb3J0KFwiLi9iYXNlLmpzXCIpLmRlZmF1bHQ+fSBxdWVyeSAtIEV2ZW50IHF1ZXJ5LlxuICogQHJldHVybnMge3ZvaWR9XG4gKi9cbmZ1bmN0aW9uIGFzc2VydEZyb250ZW5kTW9kZWxFdmVudFF1ZXJ5Q2xhc3MobW9kZWxDbGFzcywgcXVlcnkpIHtcbiAgaWYgKHF1ZXJ5Lm1vZGVsQ2xhc3MgPT09IG1vZGVsQ2xhc3MpIHJldHVyblxuXG4gIHRocm93IG5ldyBFcnJvcihgQ2Fubm90IHN1YnNjcmliZSAke21vZGVsQ2xhc3MubmFtZX0gZXZlbnRzIHdpdGggYSAke3F1ZXJ5Lm1vZGVsQ2xhc3MubmFtZX0gcXVlcnlgKVxufVxuXG4vKipcbiAqIFJ1bnMgYXNzZXJ0IGZyb250ZW5kIG1vZGVsIGV2ZW50IG9wdGlvbnMgb2JqZWN0LlxuICogQHBhcmFtIHtGcm9udGVuZE1vZGVsRXZlbnRPcHRpb25zfSBvcHRpb25zIC0gQ2FuZGlkYXRlIGV2ZW50IG9wdGlvbnMuXG4gKiBAcmV0dXJucyB7dm9pZH1cbiAqL1xuZnVuY3Rpb24gYXNzZXJ0RnJvbnRlbmRNb2RlbEV2ZW50T3B0aW9uc09iamVjdChvcHRpb25zKSB7XG4gIGlmIChvcHRpb25zICYmIHR5cGVvZiBvcHRpb25zID09PSBcIm9iamVjdFwiICYmICFBcnJheS5pc0FycmF5KG9wdGlvbnMpKSByZXR1cm5cblxuICB0aHJvdyBuZXcgRXJyb3IoYEZyb250ZW5kIG1vZGVsIGV2ZW50IG9wdGlvbnMgbXVzdCBiZSBhIHF1ZXJ5IG9yIGFuIG9wdGlvbnMgb2JqZWN0LCBnb3Q6ICR7b3B0aW9uc31gKVxufVxuXG4vKipcbiAqIFJ1bnMgY2xvbmVkIGZyb250ZW5kIG1vZGVsIGV2ZW50IHF1ZXJ5LlxuICogQHBhcmFtIHt0eXBlb2YgaW1wb3J0KFwiLi9iYXNlLmpzXCIpLmRlZmF1bHR9IG1vZGVsQ2xhc3MgLSBGcm9udGVuZCBtb2RlbCBjbGFzcy5cbiAqIEBwYXJhbSB7RnJvbnRlbmRNb2RlbFF1ZXJ5PHR5cGVvZiBpbXBvcnQoXCIuL2Jhc2UuanNcIikuZGVmYXVsdD59IHF1ZXJ5IC0gRXZlbnQgcXVlcnkuXG4gKiBAcmV0dXJucyB7RnJvbnRlbmRNb2RlbFF1ZXJ5PHR5cGVvZiBpbXBvcnQoXCIuL2Jhc2UuanNcIikuZGVmYXVsdD59IC0gQ2xvbmVkIHF1ZXJ5IHVzZWQgYnkgZXZlbnQgc3Vic2NyaXB0aW9ucy5cbiAqL1xuZnVuY3Rpb24gY2xvbmVkRnJvbnRlbmRNb2RlbEV2ZW50UXVlcnkobW9kZWxDbGFzcywgcXVlcnkpIHtcbiAgYXNzZXJ0RnJvbnRlbmRNb2RlbEV2ZW50UXVlcnlDbGFzcyhtb2RlbENsYXNzLCBxdWVyeSlcblxuICByZXR1cm4gcXVlcnkuY2xvbmUoKVxufVxuXG4vKipcbiAqIFJ1bnMgZnJvbnRlbmQgbW9kZWwgZXZlbnQgcXVlcnkgZnJvbSBvcHRpb25zIG9iamVjdC5cbiAqIEBwYXJhbSB7dHlwZW9mIGltcG9ydChcIi4vYmFzZS5qc1wiKS5kZWZhdWx0fSBtb2RlbENsYXNzIC0gRnJvbnRlbmQgbW9kZWwgY2xhc3MuXG4gKiBAcGFyYW0ge0Zyb250ZW5kTW9kZWxFdmVudE9wdGlvbnNPYmplY3R9IG9wdGlvbnMgLSBFdmVudCBvcHRpb25zIG9iamVjdC5cbiAqIEByZXR1cm5zIHtGcm9udGVuZE1vZGVsUXVlcnk8dHlwZW9mIGltcG9ydChcIi4vYmFzZS5qc1wiKS5kZWZhdWx0Pn0gLSBRdWVyeSB1c2VkIGJ5IGV2ZW50IHN1YnNjcmlwdGlvbnMuXG4gKi9cbmZ1bmN0aW9uIGZyb250ZW5kTW9kZWxFdmVudFF1ZXJ5RnJvbU9wdGlvbnNPYmplY3QobW9kZWxDbGFzcywgb3B0aW9ucykge1xuICBpZiAob3B0aW9ucy5xdWVyeSAhPT0gdW5kZWZpbmVkICYmICEob3B0aW9ucy5xdWVyeSBpbnN0YW5jZW9mIEZyb250ZW5kTW9kZWxRdWVyeSkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJGcm9udGVuZCBtb2RlbCBldmVudCBvcHRpb24gcXVlcnkgbXVzdCBiZSBhIEZyb250ZW5kTW9kZWxRdWVyeVwiKVxuICB9XG5cbiAgY29uc3QgcXVlcnkgPSBvcHRpb25zLnF1ZXJ5XG4gICAgPyBvcHRpb25zLnF1ZXJ5LmNsb25lKClcbiAgICA6IG5ldyBGcm9udGVuZE1vZGVsUXVlcnkoe21vZGVsQ2xhc3N9KVxuXG4gIGFzc2VydEZyb250ZW5kTW9kZWxFdmVudFF1ZXJ5Q2xhc3MobW9kZWxDbGFzcywgcXVlcnkpXG5cbiAgcmV0dXJuIHF1ZXJ5XG59XG5cbi8qKlxuICogUnVucyBmcm9udGVuZCBtb2RlbCBldmVudCBxdWVyeS5cbiAqIEBwYXJhbSB7dHlwZW9mIGltcG9ydChcIi4vYmFzZS5qc1wiKS5kZWZhdWx0fSBtb2RlbENsYXNzIC0gRnJvbnRlbmQgbW9kZWwgY2xhc3MuXG4gKiBAcGFyYW0ge0Zyb250ZW5kTW9kZWxFdmVudE9wdGlvbnN9IFtvcHRpb25zXSAtIEV2ZW50IHF1ZXJ5IG9yIHByb2plY3Rpb24gb3B0aW9ucy5cbiAqIEByZXR1cm5zIHtGcm9udGVuZE1vZGVsUXVlcnk8dHlwZW9mIGltcG9ydChcIi4vYmFzZS5qc1wiKS5kZWZhdWx0Pn0gLSBOb3JtYWxpemVkIHF1ZXJ5IHVzZWQgYnkgZXZlbnQgc3Vic2NyaXB0aW9ucy5cbiAqL1xuZnVuY3Rpb24gZnJvbnRlbmRNb2RlbEV2ZW50UXVlcnkobW9kZWxDbGFzcywgb3B0aW9ucyA9IHt9KSB7XG4gIGlmIChvcHRpb25zIGluc3RhbmNlb2YgRnJvbnRlbmRNb2RlbFF1ZXJ5KSByZXR1cm4gY2xvbmVkRnJvbnRlbmRNb2RlbEV2ZW50UXVlcnkobW9kZWxDbGFzcywgb3B0aW9ucylcblxuICBhc3NlcnRGcm9udGVuZE1vZGVsRXZlbnRPcHRpb25zT2JqZWN0KG9wdGlvbnMpXG5cbiAgY29uc3Qgb3B0aW9uc09iamVjdCA9IC8qKlxuICAgICAgICAgICAgICAgICAgICAgICAgICogTmFycm93cyB0aGUgcnVudGltZSB2YWx1ZSB0byB0aGUgZG9jdW1lbnRlZCB0eXBlLlxuICAgICAgICAgICAgICAgICAgICAgICAgICBAdHlwZSB7RnJvbnRlbmRNb2RlbEV2ZW50T3B0aW9uc09iamVjdH0gKi8gKG9wdGlvbnMpXG4gIGNvbnN0IHF1ZXJ5ID0gZnJvbnRlbmRNb2RlbEV2ZW50UXVlcnlGcm9tT3B0aW9uc09iamVjdChtb2RlbENsYXNzLCBvcHRpb25zT2JqZWN0KVxuXG4gIGFwcGx5RnJvbnRlbmRNb2RlbFByb2plY3Rpb25PcHRpb25zKHF1ZXJ5LCBvcHRpb25zT2JqZWN0KVxuXG4gIHJldHVybiBxdWVyeVxufVxuXG4vKipcbiAqIFJ1bnMgdGhlIGZyb250ZW5kTW9kZWxFdmVudE9wdGlvbnNQYXlsb2FkIGhlbHBlci5cbiAqIEBwYXJhbSB7dHlwZW9mIGltcG9ydChcIi4vYmFzZS5qc1wiKS5kZWZhdWx0fSBtb2RlbENsYXNzIC0gRnJvbnRlbmQgbW9kZWwgY2xhc3MuXG4gKiBAcGFyYW0ge0Zyb250ZW5kTW9kZWxFdmVudE9wdGlvbnN9IFtvcHRpb25zXSAtIEV2ZW50IHF1ZXJ5IG9yIHByb2plY3Rpb24gb3B0aW9ucy5cbiAqIEByZXR1cm5zIHtGcm9udGVuZE1vZGVsRXZlbnRPcHRpb25zUGF5bG9hZH0gLSBOb3JtYWxpemVkIGV2ZW50IHN1YnNjcmlwdGlvbiBwYXlsb2FkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZnJvbnRlbmRNb2RlbEV2ZW50T3B0aW9uc1BheWxvYWQobW9kZWxDbGFzcywgb3B0aW9ucyA9IHt9KSB7XG4gIHJldHVybiBmcm9udGVuZE1vZGVsRXZlbnRRdWVyeShtb2RlbENsYXNzLCBvcHRpb25zKS5ldmVudE9wdGlvbnNQYXlsb2FkKClcbn1cbiJdfQ==