velocious 1.0.430 → 1.0.431

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 (811) hide show
  1. package/bin/velocious.js +48 -0
  2. package/build/bin/velocious.js +39 -34
  3. package/build/index.js +1 -2
  4. package/build/src/application.js +214 -187
  5. package/build/src/authorization/ability.d.ts +24 -23
  6. package/build/src/authorization/ability.d.ts.map +1 -1
  7. package/build/src/authorization/ability.js +300 -252
  8. package/build/src/authorization/base-resource.d.ts +20 -26
  9. package/build/src/authorization/base-resource.d.ts.map +1 -1
  10. package/build/src/authorization/base-resource.js +136 -118
  11. package/build/src/background-jobs/client.js +47 -43
  12. package/build/src/background-jobs/cron-expression.js +166 -127
  13. package/build/src/background-jobs/forked-runner-child.js +47 -37
  14. package/build/src/background-jobs/job-record.js +10 -8
  15. package/build/src/background-jobs/job-registry.js +84 -72
  16. package/build/src/background-jobs/job-runner.js +81 -74
  17. package/build/src/background-jobs/job.js +72 -62
  18. package/build/src/background-jobs/json-socket.js +70 -65
  19. package/build/src/background-jobs/main.js +900 -841
  20. package/build/src/background-jobs/normalize-error.js +11 -12
  21. package/build/src/background-jobs/scheduler.js +247 -205
  22. package/build/src/background-jobs/socket-request.js +65 -60
  23. package/build/src/background-jobs/status-reporter.js +96 -86
  24. package/build/src/background-jobs/store.js +980 -862
  25. package/build/src/background-jobs/types.js +3 -2
  26. package/build/src/background-jobs/web/authorization.js +50 -38
  27. package/build/src/background-jobs/web/controller.js +268 -232
  28. package/build/src/background-jobs/web/index.js +40 -36
  29. package/build/src/background-jobs/web/path-matcher.js +48 -45
  30. package/build/src/background-jobs/web/registry.js +14 -9
  31. package/build/src/background-jobs/worker.js +639 -585
  32. package/build/src/beacon/client.js +293 -264
  33. package/build/src/beacon/in-process-broker.js +25 -20
  34. package/build/src/beacon/in-process-client.js +116 -104
  35. package/build/src/beacon/server.js +126 -110
  36. package/build/src/beacon/types.js +8 -2
  37. package/build/src/cli/base-command.js +57 -49
  38. package/build/src/cli/browser-cli.js +42 -37
  39. package/build/src/cli/commands/background-jobs-main.js +5 -5
  40. package/build/src/cli/commands/background-jobs-runner.js +5 -5
  41. package/build/src/cli/commands/background-jobs-worker.js +5 -5
  42. package/build/src/cli/commands/beacon.js +5 -5
  43. package/build/src/cli/commands/console.js +10 -10
  44. package/build/src/cli/commands/db/base-command.js +76 -71
  45. package/build/src/cli/commands/db/create.js +61 -53
  46. package/build/src/cli/commands/db/drop.js +71 -62
  47. package/build/src/cli/commands/db/migrate.js +15 -13
  48. package/build/src/cli/commands/db/reset.js +19 -16
  49. package/build/src/cli/commands/db/rollback.js +13 -12
  50. package/build/src/cli/commands/db/schema/dump.js +9 -9
  51. package/build/src/cli/commands/db/schema/load.js +9 -9
  52. package/build/src/cli/commands/db/seed.js +9 -9
  53. package/build/src/cli/commands/db/tenants/check.js +35 -32
  54. package/build/src/cli/commands/db/tenants/create.js +29 -26
  55. package/build/src/cli/commands/db/tenants/migrate.js +44 -40
  56. package/build/src/cli/commands/destroy/migration.js +5 -5
  57. package/build/src/cli/commands/generate/base-models.js +5 -5
  58. package/build/src/cli/commands/generate/frontend-models.js +9 -9
  59. package/build/src/cli/commands/generate/migration.js +5 -5
  60. package/build/src/cli/commands/generate/model.js +5 -5
  61. package/build/src/cli/commands/init.js +9 -7
  62. package/build/src/cli/commands/routes.js +6 -6
  63. package/build/src/cli/commands/run-script.js +9 -9
  64. package/build/src/cli/commands/runner.js +9 -9
  65. package/build/src/cli/commands/server.js +6 -6
  66. package/build/src/cli/commands/test.js +7 -6
  67. package/build/src/cli/index.js +141 -127
  68. package/build/src/cli/tenant-database-command-helper.js +185 -154
  69. package/build/src/cli/use-browser-cli.js +20 -15
  70. package/build/src/configuration-resolver.js +54 -47
  71. package/build/src/configuration-types.d.ts +21 -2
  72. package/build/src/configuration-types.d.ts.map +1 -1
  73. package/build/src/configuration-types.js +60 -3
  74. package/build/src/configuration.js +2547 -2240
  75. package/build/src/controller.js +407 -363
  76. package/build/src/current-configuration.js +12 -9
  77. package/build/src/current.js +75 -70
  78. package/build/src/database/annotations-async-hooks.js +22 -16
  79. package/build/src/database/annotations.js +18 -12
  80. package/build/src/database/drivers/base-column.js +179 -155
  81. package/build/src/database/drivers/base-columns-index.js +78 -69
  82. package/build/src/database/drivers/base-foreign-key.js +101 -89
  83. package/build/src/database/drivers/base-table.js +149 -124
  84. package/build/src/database/drivers/base.js +1489 -1306
  85. package/build/src/database/drivers/mssql/column.js +50 -39
  86. package/build/src/database/drivers/mssql/columns-index.js +3 -2
  87. package/build/src/database/drivers/mssql/connect-connection.js +9 -11
  88. package/build/src/database/drivers/mssql/foreign-key.js +9 -8
  89. package/build/src/database/drivers/mssql/index.js +587 -507
  90. package/build/src/database/drivers/mssql/options.js +75 -68
  91. package/build/src/database/drivers/mssql/query-parser.js +3 -2
  92. package/build/src/database/drivers/mssql/sql/alter-table.js +2 -2
  93. package/build/src/database/drivers/mssql/sql/create-database.js +31 -24
  94. package/build/src/database/drivers/mssql/sql/create-index.js +2 -2
  95. package/build/src/database/drivers/mssql/sql/create-table.js +2 -2
  96. package/build/src/database/drivers/mssql/sql/delete.js +16 -14
  97. package/build/src/database/drivers/mssql/sql/drop-database.js +31 -24
  98. package/build/src/database/drivers/mssql/sql/drop-table.js +2 -2
  99. package/build/src/database/drivers/mssql/sql/insert.js +2 -2
  100. package/build/src/database/drivers/mssql/sql/update.js +28 -24
  101. package/build/src/database/drivers/mssql/sql/upsert.js +20 -18
  102. package/build/src/database/drivers/mssql/structure-sql.js +114 -102
  103. package/build/src/database/drivers/mssql/table.js +96 -81
  104. package/build/src/database/drivers/mysql/column.js +92 -75
  105. package/build/src/database/drivers/mysql/columns-index.js +19 -16
  106. package/build/src/database/drivers/mysql/foreign-key.js +9 -8
  107. package/build/src/database/drivers/mysql/index.js +457 -396
  108. package/build/src/database/drivers/mysql/options.js +30 -26
  109. package/build/src/database/drivers/mysql/query-parser.js +3 -2
  110. package/build/src/database/drivers/mysql/query.js +29 -26
  111. package/build/src/database/drivers/mysql/sql/alter-table.js +3 -2
  112. package/build/src/database/drivers/mysql/sql/create-database.js +28 -23
  113. package/build/src/database/drivers/mysql/sql/create-index.js +3 -2
  114. package/build/src/database/drivers/mysql/sql/create-table.js +3 -2
  115. package/build/src/database/drivers/mysql/sql/delete.js +17 -14
  116. package/build/src/database/drivers/mysql/sql/drop-database.js +3 -2
  117. package/build/src/database/drivers/mysql/sql/drop-table.js +3 -2
  118. package/build/src/database/drivers/mysql/sql/insert.js +3 -2
  119. package/build/src/database/drivers/mysql/sql/update.js +29 -24
  120. package/build/src/database/drivers/mysql/sql/upsert.js +10 -8
  121. package/build/src/database/drivers/mysql/structure-sql.js +88 -79
  122. package/build/src/database/drivers/mysql/table.js +98 -83
  123. package/build/src/database/drivers/pgsql/column.js +72 -56
  124. package/build/src/database/drivers/pgsql/columns-index.js +3 -2
  125. package/build/src/database/drivers/pgsql/foreign-key.js +9 -8
  126. package/build/src/database/drivers/pgsql/index.js +438 -377
  127. package/build/src/database/drivers/pgsql/options.js +28 -25
  128. package/build/src/database/drivers/pgsql/query-parser.js +3 -2
  129. package/build/src/database/drivers/pgsql/sql/alter-table.js +3 -2
  130. package/build/src/database/drivers/pgsql/sql/create-database.js +23 -19
  131. package/build/src/database/drivers/pgsql/sql/create-index.js +3 -2
  132. package/build/src/database/drivers/pgsql/sql/create-table.js +3 -2
  133. package/build/src/database/drivers/pgsql/sql/delete.js +17 -14
  134. package/build/src/database/drivers/pgsql/sql/drop-database.js +3 -2
  135. package/build/src/database/drivers/pgsql/sql/drop-table.js +3 -2
  136. package/build/src/database/drivers/pgsql/sql/insert.js +3 -2
  137. package/build/src/database/drivers/pgsql/sql/update.js +29 -24
  138. package/build/src/database/drivers/pgsql/sql/upsert.js +11 -9
  139. package/build/src/database/drivers/pgsql/structure-sql.js +120 -108
  140. package/build/src/database/drivers/pgsql/table.js +77 -60
  141. package/build/src/database/drivers/sqlite/base.js +478 -405
  142. package/build/src/database/drivers/sqlite/column.js +69 -54
  143. package/build/src/database/drivers/sqlite/columns-index.js +27 -22
  144. package/build/src/database/drivers/sqlite/connection-sql-js.js +42 -35
  145. package/build/src/database/drivers/sqlite/foreign-key.js +21 -18
  146. package/build/src/database/drivers/sqlite/index.js +373 -330
  147. package/build/src/database/drivers/sqlite/index.native.js +64 -55
  148. package/build/src/database/drivers/sqlite/index.web.js +87 -69
  149. package/build/src/database/drivers/sqlite/options.js +28 -25
  150. package/build/src/database/drivers/sqlite/query-parser.js +3 -2
  151. package/build/src/database/drivers/sqlite/query.js +24 -21
  152. package/build/src/database/drivers/sqlite/query.native.js +25 -20
  153. package/build/src/database/drivers/sqlite/query.web.js +37 -30
  154. package/build/src/database/drivers/sqlite/sql/alter-table.js +179 -159
  155. package/build/src/database/drivers/sqlite/sql/create-index.js +3 -2
  156. package/build/src/database/drivers/sqlite/sql/create-table.js +3 -2
  157. package/build/src/database/drivers/sqlite/sql/delete.js +22 -17
  158. package/build/src/database/drivers/sqlite/sql/drop-table.js +3 -2
  159. package/build/src/database/drivers/sqlite/sql/insert.js +3 -2
  160. package/build/src/database/drivers/sqlite/sql/update.js +29 -24
  161. package/build/src/database/drivers/sqlite/sql/upsert.js +11 -9
  162. package/build/src/database/drivers/sqlite/structure-sql.js +52 -49
  163. package/build/src/database/drivers/sqlite/table-rebuilder.js +75 -62
  164. package/build/src/database/drivers/sqlite/table.js +125 -102
  165. package/build/src/database/drivers/structure-sql/utils.js +17 -14
  166. package/build/src/database/handler.js +10 -9
  167. package/build/src/database/initializer-from-require-context.js +87 -76
  168. package/build/src/database/migration/index.js +395 -332
  169. package/build/src/database/migrator/files-finder.js +50 -40
  170. package/build/src/database/migrator/types.js +30 -2
  171. package/build/src/database/migrator.js +526 -454
  172. package/build/src/database/pool/async-tracked-multi-connection.js +1147 -997
  173. package/build/src/database/pool/base-methods-forward.js +43 -40
  174. package/build/src/database/pool/base.js +343 -298
  175. package/build/src/database/pool/single-multi-use.js +110 -93
  176. package/build/src/database/query/alter-table-base.js +99 -84
  177. package/build/src/database/query/base.js +46 -39
  178. package/build/src/database/query/create-database-base.js +30 -25
  179. package/build/src/database/query/create-index-base.js +94 -75
  180. package/build/src/database/query/create-table-base.js +193 -151
  181. package/build/src/database/query/delete-base.js +16 -14
  182. package/build/src/database/query/drop-database-base.js +28 -23
  183. package/build/src/database/query/drop-table-base.js +53 -42
  184. package/build/src/database/query/from-base.js +33 -30
  185. package/build/src/database/query/from-plain.js +13 -11
  186. package/build/src/database/query/from-table.js +15 -13
  187. package/build/src/database/query/index.js +472 -410
  188. package/build/src/database/query/insert-base.js +164 -143
  189. package/build/src/database/query/join-base.js +40 -35
  190. package/build/src/database/query/join-object.js +153 -128
  191. package/build/src/database/query/join-plain.js +15 -13
  192. package/build/src/database/query/join-tracker.js +90 -76
  193. package/build/src/database/query/model-class-query.js +1370 -1134
  194. package/build/src/database/query/order-base.js +30 -27
  195. package/build/src/database/query/order-column.js +53 -44
  196. package/build/src/database/query/order-plain.js +24 -20
  197. package/build/src/database/query/preloader/belongs-to.js +258 -210
  198. package/build/src/database/query/preloader/ensure-model-class-initialized.js +9 -8
  199. package/build/src/database/query/preloader/has-many.js +301 -240
  200. package/build/src/database/query/preloader/has-one.js +117 -91
  201. package/build/src/database/query/preloader/selection.js +129 -117
  202. package/build/src/database/query/preloader.js +185 -160
  203. package/build/src/database/query/query-data.js +201 -157
  204. package/build/src/database/query/select-base.js +27 -25
  205. package/build/src/database/query/select-plain.js +15 -13
  206. package/build/src/database/query/select-table-and-column.js +25 -21
  207. package/build/src/database/query/update-base.js +38 -35
  208. package/build/src/database/query/upsert-base.js +100 -93
  209. package/build/src/database/query/where-base.js +35 -32
  210. package/build/src/database/query/where-combinator.d.ts.map +1 -1
  211. package/build/src/database/query/where-combinator.js +28 -26
  212. package/build/src/database/query/where-hash.js +68 -61
  213. package/build/src/database/query/where-model-class-hash.js +469 -414
  214. package/build/src/database/query/where-not.js +20 -18
  215. package/build/src/database/query/where-plain.js +17 -15
  216. package/build/src/database/query/with-count.js +159 -125
  217. package/build/src/database/query-parser/base-query-parser.js +37 -32
  218. package/build/src/database/query-parser/from-parser.js +45 -36
  219. package/build/src/database/query-parser/group-parser.js +50 -42
  220. package/build/src/database/query-parser/joins-parser.js +33 -28
  221. package/build/src/database/query-parser/limit-parser.js +70 -67
  222. package/build/src/database/query-parser/options.js +82 -75
  223. package/build/src/database/query-parser/order-parser.js +40 -36
  224. package/build/src/database/query-parser/select-parser.js +60 -49
  225. package/build/src/database/query-parser/where-parser.js +41 -36
  226. package/build/src/database/record/acts-as-list.js +273 -235
  227. package/build/src/database/record/attachments/download.js +45 -44
  228. package/build/src/database/record/attachments/handle.js +161 -141
  229. package/build/src/database/record/attachments/normalize-input.js +138 -128
  230. package/build/src/database/record/attachments/storage-drivers/filesystem.js +91 -77
  231. package/build/src/database/record/attachments/storage-drivers/native.js +121 -112
  232. package/build/src/database/record/attachments/storage-drivers/s3.js +208 -177
  233. package/build/src/database/record/attachments/store.d.ts +1 -1
  234. package/build/src/database/record/attachments/store.d.ts.map +1 -1
  235. package/build/src/database/record/attachments/store.js +540 -468
  236. package/build/src/database/record/index.d.ts +17 -15
  237. package/build/src/database/record/index.d.ts.map +1 -1
  238. package/build/src/database/record/index.js +3894 -3361
  239. package/build/src/database/record/instance-relationships/base.js +268 -234
  240. package/build/src/database/record/instance-relationships/belongs-to.js +73 -58
  241. package/build/src/database/record/instance-relationships/has-many.js +264 -225
  242. package/build/src/database/record/instance-relationships/has-one.js +105 -85
  243. package/build/src/database/record/record-not-found-error.js +2 -3
  244. package/build/src/database/record/relationships/base.d.ts +2 -2
  245. package/build/src/database/record/relationships/base.d.ts.map +1 -1
  246. package/build/src/database/record/relationships/base.js +167 -145
  247. package/build/src/database/record/relationships/belongs-to.js +51 -44
  248. package/build/src/database/record/relationships/has-many.js +40 -32
  249. package/build/src/database/record/relationships/has-one.js +40 -32
  250. package/build/src/database/record/state-machine.js +208 -156
  251. package/build/src/database/record/user-module.js +38 -32
  252. package/build/src/database/record/validators/base.js +24 -22
  253. package/build/src/database/record/validators/format.js +46 -36
  254. package/build/src/database/record/validators/presence.js +20 -18
  255. package/build/src/database/record/validators/uniqueness.js +117 -99
  256. package/build/src/database/table-data/index.js +231 -199
  257. package/build/src/database/table-data/table-column.js +382 -338
  258. package/build/src/database/table-data/table-foreign-key.js +66 -57
  259. package/build/src/database/table-data/table-index.js +36 -29
  260. package/build/src/database/table-data/table-reference.js +10 -10
  261. package/build/src/database/use-database.js +40 -32
  262. package/build/src/environment-handlers/base.js +544 -484
  263. package/build/src/environment-handlers/browser.js +294 -241
  264. package/build/src/environment-handlers/node/cli/commands/background-jobs-main.js +19 -16
  265. package/build/src/environment-handlers/node/cli/commands/background-jobs-runner.js +21 -18
  266. package/build/src/environment-handlers/node/cli/commands/background-jobs-worker.js +29 -22
  267. package/build/src/environment-handlers/node/cli/commands/beacon.js +19 -16
  268. package/build/src/environment-handlers/node/cli/commands/cli-command-context.js +15 -14
  269. package/build/src/environment-handlers/node/cli/commands/console.js +120 -99
  270. package/build/src/environment-handlers/node/cli/commands/db/schema/dump.js +39 -34
  271. package/build/src/environment-handlers/node/cli/commands/db/schema/load.js +63 -57
  272. package/build/src/environment-handlers/node/cli/commands/db/seed.js +63 -51
  273. package/build/src/environment-handlers/node/cli/commands/destroy/migration.js +40 -32
  274. package/build/src/environment-handlers/node/cli/commands/generate/base-models.d.ts.map +1 -1
  275. package/build/src/environment-handlers/node/cli/commands/generate/base-models.js +353 -298
  276. package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.js +844 -729
  277. package/build/src/environment-handlers/node/cli/commands/generate/migration.js +38 -34
  278. package/build/src/environment-handlers/node/cli/commands/generate/model.js +38 -34
  279. package/build/src/environment-handlers/node/cli/commands/init.js +61 -56
  280. package/build/src/environment-handlers/node/cli/commands/routes.js +59 -51
  281. package/build/src/environment-handlers/node/cli/commands/run-script.js +68 -54
  282. package/build/src/environment-handlers/node/cli/commands/runner.js +74 -56
  283. package/build/src/environment-handlers/node/cli/commands/server.js +106 -93
  284. package/build/src/environment-handlers/node/cli/commands/test.js +113 -97
  285. package/build/src/environment-handlers/node.js +874 -753
  286. package/build/src/error-logger.js +21 -22
  287. package/build/src/frontend-model-controller.d.ts +6 -6
  288. package/build/src/frontend-model-controller.d.ts.map +1 -1
  289. package/build/src/frontend-model-controller.js +3288 -2788
  290. package/build/src/frontend-model-resource/base-resource.d.ts +18 -17
  291. package/build/src/frontend-model-resource/base-resource.d.ts.map +1 -1
  292. package/build/src/frontend-model-resource/base-resource.js +869 -759
  293. package/build/src/frontend-models/base.d.ts +19 -12
  294. package/build/src/frontend-models/base.d.ts.map +1 -1
  295. package/build/src/frontend-models/base.js +3602 -3114
  296. package/build/src/frontend-models/clear-pending-debounced-callback.js +8 -7
  297. package/build/src/frontend-models/event-hook-models.js +21 -16
  298. package/build/src/frontend-models/model-registry.js +11 -9
  299. package/build/src/frontend-models/outgoing-event-buffer.js +17 -10
  300. package/build/src/frontend-models/preloader.d.ts +6 -6
  301. package/build/src/frontend-models/preloader.d.ts.map +1 -1
  302. package/build/src/frontend-models/preloader.js +149 -131
  303. package/build/src/frontend-models/query.d.ts.map +1 -1
  304. package/build/src/frontend-models/query.js +1855 -1560
  305. package/build/src/frontend-models/resource-config-validation.js +37 -27
  306. package/build/src/frontend-models/resource-definition.js +288 -234
  307. package/build/src/frontend-models/transport-serialization.js +266 -203
  308. package/build/src/frontend-models/use-created-event.js +7 -5
  309. package/build/src/frontend-models/use-destroyed-event.js +93 -80
  310. package/build/src/frontend-models/use-model-class-event.js +91 -79
  311. package/build/src/frontend-models/use-updated-event.js +97 -84
  312. package/build/src/frontend-models/websocket-channel.js +441 -381
  313. package/build/src/frontend-models/websocket-publishers.js +173 -140
  314. package/build/src/http-client/header.js +14 -13
  315. package/build/src/http-client/index.js +132 -116
  316. package/build/src/http-client/request.js +87 -71
  317. package/build/src/http-client/response.js +140 -122
  318. package/build/src/http-client/websocket-client.js +17 -15
  319. package/build/src/http-server/client/index.js +465 -409
  320. package/build/src/http-server/client/params-to-object.js +135 -124
  321. package/build/src/http-server/client/request-buffer/form-data-part.js +132 -111
  322. package/build/src/http-server/client/request-buffer/header.js +16 -15
  323. package/build/src/http-server/client/request-buffer/index.js +506 -446
  324. package/build/src/http-server/client/request-parser.js +186 -163
  325. package/build/src/http-server/client/request-runner.js +259 -226
  326. package/build/src/http-server/client/request-timing.js +151 -132
  327. package/build/src/http-server/client/request.js +108 -96
  328. package/build/src/http-server/client/response.js +235 -213
  329. package/build/src/http-server/client/uploaded-file/memory-uploaded-file.js +29 -25
  330. package/build/src/http-server/client/uploaded-file/temporary-uploaded-file.js +29 -25
  331. package/build/src/http-server/client/uploaded-file/uploaded-file.js +33 -33
  332. package/build/src/http-server/client/websocket-request.js +137 -114
  333. package/build/src/http-server/client/websocket-session.js +1657 -1452
  334. package/build/src/http-server/cookie.js +236 -216
  335. package/build/src/http-server/development-reloader.js +221 -190
  336. package/build/src/http-server/index.js +525 -451
  337. package/build/src/http-server/remote-address.js +50 -38
  338. package/build/src/http-server/server-client.js +208 -181
  339. package/build/src/http-server/server-lock.js +167 -153
  340. package/build/src/http-server/websocket-channel-subscribers.js +93 -81
  341. package/build/src/http-server/websocket-channel.js +117 -104
  342. package/build/src/http-server/websocket-connection.js +104 -96
  343. package/build/src/http-server/websocket-event-log-store.js +404 -350
  344. package/build/src/http-server/websocket-events-host.js +164 -145
  345. package/build/src/http-server/websocket-events.js +47 -47
  346. package/build/src/http-server/worker-handler/channel-subscriber-dispatch.js +14 -13
  347. package/build/src/http-server/worker-handler/in-process.js +141 -123
  348. package/build/src/http-server/worker-handler/index.js +349 -313
  349. package/build/src/http-server/worker-handler/worker-script.js +5 -4
  350. package/build/src/http-server/worker-handler/worker-thread.js +269 -240
  351. package/build/src/initializer.js +36 -31
  352. package/build/src/jobs/mail-delivery.js +15 -13
  353. package/build/src/logger/base-logger.js +26 -24
  354. package/build/src/logger/console-logger.js +23 -21
  355. package/build/src/logger/file-logger.js +31 -29
  356. package/build/src/logger/outputs/array-output.js +42 -37
  357. package/build/src/logger/outputs/console-output.js +24 -20
  358. package/build/src/logger/outputs/file-output.js +48 -43
  359. package/build/src/logger/outputs/stdout-output.js +48 -39
  360. package/build/src/logger.js +394 -338
  361. package/build/src/mailer/backends/smtp.js +163 -134
  362. package/build/src/mailer/base.js +251 -211
  363. package/build/src/mailer/delivery.js +64 -56
  364. package/build/src/mailer/index.js +22 -4
  365. package/build/src/mailer.js +13 -4
  366. package/build/src/plugins/sqljs-wasm-route-controller.js +52 -42
  367. package/build/src/plugins/sqljs-wasm-route.js +38 -28
  368. package/build/src/record-payload-values.js +28 -25
  369. package/build/src/routes/app-routes.js +14 -12
  370. package/build/src/routes/base-route.js +130 -112
  371. package/build/src/routes/basic-route.js +102 -83
  372. package/build/src/routes/built-in/debug/controller.js +10 -10
  373. package/build/src/routes/built-in/errors/controller.js +5 -5
  374. package/build/src/routes/get-route.js +63 -50
  375. package/build/src/routes/hooks/frontend-model-command-route-hook.js +80 -66
  376. package/build/src/routes/index.js +43 -36
  377. package/build/src/routes/namespace-route.js +47 -38
  378. package/build/src/routes/plugin-routes.js +124 -107
  379. package/build/src/routes/post-route.js +62 -51
  380. package/build/src/routes/resolver.js +494 -422
  381. package/build/src/routes/resource-route.js +143 -124
  382. package/build/src/routes/root-route.js +8 -7
  383. package/build/src/testing/base-expect.js +14 -13
  384. package/build/src/testing/browser-frontend-model-event-hook-scenarios.js +405 -329
  385. package/build/src/testing/browser-test-app.js +29 -23
  386. package/build/src/testing/expect-to-change.js +50 -41
  387. package/build/src/testing/expect-utils.js +184 -139
  388. package/build/src/testing/expect.js +731 -638
  389. package/build/src/testing/request-client.js +85 -70
  390. package/build/src/testing/test-files-finder.js +339 -285
  391. package/build/src/testing/test-filter-parser.js +155 -124
  392. package/build/src/testing/test-runner.js +1020 -883
  393. package/build/src/testing/test-suite-splitter.js +142 -114
  394. package/build/src/testing/test.js +256 -216
  395. package/build/src/utils/backtrace-cleaner-node.js +69 -62
  396. package/build/src/utils/backtrace-cleaner.js +216 -188
  397. package/build/src/utils/ensure-error.js +7 -7
  398. package/build/src/utils/event-emitter.js +6 -4
  399. package/build/src/utils/file-exists.js +10 -9
  400. package/build/src/utils/format-value.js +76 -67
  401. package/build/src/utils/model-scope.js +31 -27
  402. package/build/src/utils/nest-callbacks.js +13 -10
  403. package/build/src/utils/plain-object.js +6 -5
  404. package/build/src/utils/ransack.d.ts.map +1 -1
  405. package/build/src/utils/ransack.js +563 -449
  406. package/build/src/utils/rest-args-error.js +6 -5
  407. package/build/src/utils/singularize-model-name.js +11 -9
  408. package/build/src/utils/split-sql-statements.js +79 -68
  409. package/build/src/utils/to-import-specifier.js +30 -24
  410. package/build/src/utils/with-tracked-stack-async-hooks.js +74 -60
  411. package/build/src/utils/with-tracked-stack.js +18 -14
  412. package/build/src/velocious-error.js +30 -27
  413. package/index.js +1 -0
  414. package/package.json +10 -4
  415. package/scripts/clean-build.js +8 -0
  416. package/scripts/ensure-bin-executable.js +13 -0
  417. package/scripts/run-tests.js +37 -0
  418. package/scripts/test-browser.js +486 -0
  419. package/src/application.js +229 -0
  420. package/src/authorization/ability.js +329 -0
  421. package/src/authorization/base-resource.js +143 -0
  422. package/src/background-jobs/client.js +50 -0
  423. package/src/background-jobs/cron-expression.js +277 -0
  424. package/src/background-jobs/forked-runner-child.js +86 -0
  425. package/src/background-jobs/job-record.js +13 -0
  426. package/src/background-jobs/job-registry.js +92 -0
  427. package/src/background-jobs/job-runner.js +107 -0
  428. package/src/background-jobs/job.js +77 -0
  429. package/src/background-jobs/json-socket.js +78 -0
  430. package/src/background-jobs/main.js +926 -0
  431. package/src/background-jobs/normalize-error.js +26 -0
  432. package/src/background-jobs/scheduler.js +274 -0
  433. package/src/background-jobs/socket-request.js +68 -0
  434. package/src/background-jobs/status-reporter.js +101 -0
  435. package/src/background-jobs/store.js +994 -0
  436. package/src/background-jobs/types.js +70 -0
  437. package/src/background-jobs/web/authorization.js +89 -0
  438. package/src/background-jobs/web/controller.js +280 -0
  439. package/src/background-jobs/web/index.js +57 -0
  440. package/src/background-jobs/web/path-matcher.js +74 -0
  441. package/src/background-jobs/web/registry.js +49 -0
  442. package/src/background-jobs/worker.js +683 -0
  443. package/src/beacon/client.js +330 -0
  444. package/src/beacon/in-process-broker.js +71 -0
  445. package/src/beacon/in-process-client.js +139 -0
  446. package/src/beacon/server.js +148 -0
  447. package/src/beacon/types.js +55 -0
  448. package/src/cli/base-command.js +67 -0
  449. package/src/cli/browser-cli.js +45 -0
  450. package/src/cli/commands/background-jobs-main.js +7 -0
  451. package/src/cli/commands/background-jobs-runner.js +7 -0
  452. package/src/cli/commands/background-jobs-worker.js +7 -0
  453. package/src/cli/commands/beacon.js +7 -0
  454. package/src/cli/commands/console.js +12 -0
  455. package/src/cli/commands/db/base-command.js +82 -0
  456. package/src/cli/commands/db/create.js +64 -0
  457. package/src/cli/commands/db/drop.js +75 -0
  458. package/src/cli/commands/db/migrate.js +17 -0
  459. package/src/cli/commands/db/reset.js +22 -0
  460. package/src/cli/commands/db/rollback.js +15 -0
  461. package/src/cli/commands/db/schema/dump.js +12 -0
  462. package/src/cli/commands/db/schema/load.js +12 -0
  463. package/src/cli/commands/db/seed.js +12 -0
  464. package/src/cli/commands/db/tenants/check.js +38 -0
  465. package/src/cli/commands/db/tenants/create.js +33 -0
  466. package/src/cli/commands/db/tenants/migrate.js +49 -0
  467. package/src/cli/commands/destroy/migration.js +7 -0
  468. package/src/cli/commands/generate/base-models.js +7 -0
  469. package/src/cli/commands/generate/frontend-models.js +12 -0
  470. package/src/cli/commands/generate/migration.js +7 -0
  471. package/src/cli/commands/generate/model.js +7 -0
  472. package/src/cli/commands/init.js +11 -0
  473. package/src/cli/commands/routes.js +7 -0
  474. package/src/cli/commands/run-script.js +12 -0
  475. package/src/cli/commands/runner.js +12 -0
  476. package/src/cli/commands/server.js +7 -0
  477. package/src/cli/commands/test.js +9 -0
  478. package/src/cli/index.js +152 -0
  479. package/src/cli/tenant-database-command-helper.js +198 -0
  480. package/src/cli/use-browser-cli.js +30 -0
  481. package/src/configuration-resolver.js +65 -0
  482. package/src/configuration-types.js +429 -0
  483. package/src/configuration.js +2590 -0
  484. package/src/controller.js +421 -0
  485. package/src/current-configuration.js +31 -0
  486. package/src/current.js +80 -0
  487. package/src/database/annotations-async-hooks.js +47 -0
  488. package/src/database/annotations.js +40 -0
  489. package/src/database/drivers/base-column.js +182 -0
  490. package/src/database/drivers/base-columns-index.js +81 -0
  491. package/src/database/drivers/base-foreign-key.js +104 -0
  492. package/src/database/drivers/base-table.js +156 -0
  493. package/src/database/drivers/base.js +1609 -0
  494. package/src/database/drivers/mssql/column.js +74 -0
  495. package/src/database/drivers/mssql/columns-index.js +6 -0
  496. package/src/database/drivers/mssql/connect-connection.js +16 -0
  497. package/src/database/drivers/mssql/foreign-key.js +12 -0
  498. package/src/database/drivers/mssql/index.js +590 -0
  499. package/src/database/drivers/mssql/options.js +79 -0
  500. package/src/database/drivers/mssql/query-parser.js +6 -0
  501. package/src/database/drivers/mssql/sql/alter-table.js +4 -0
  502. package/src/database/drivers/mssql/sql/create-database.js +36 -0
  503. package/src/database/drivers/mssql/sql/create-index.js +4 -0
  504. package/src/database/drivers/mssql/sql/create-table.js +4 -0
  505. package/src/database/drivers/mssql/sql/delete.js +19 -0
  506. package/src/database/drivers/mssql/sql/drop-database.js +36 -0
  507. package/src/database/drivers/mssql/sql/drop-table.js +4 -0
  508. package/src/database/drivers/mssql/sql/insert.js +4 -0
  509. package/src/database/drivers/mssql/sql/update.js +31 -0
  510. package/src/database/drivers/mssql/sql/upsert.js +23 -0
  511. package/src/database/drivers/mssql/structure-sql.js +120 -0
  512. package/src/database/drivers/mssql/table.js +145 -0
  513. package/src/database/drivers/mysql/column.js +112 -0
  514. package/src/database/drivers/mysql/columns-index.js +22 -0
  515. package/src/database/drivers/mysql/foreign-key.js +12 -0
  516. package/src/database/drivers/mysql/index.js +473 -0
  517. package/src/database/drivers/mysql/options.js +34 -0
  518. package/src/database/drivers/mysql/query-parser.js +6 -0
  519. package/src/database/drivers/mysql/query.js +37 -0
  520. package/src/database/drivers/mysql/sql/alter-table.js +6 -0
  521. package/src/database/drivers/mysql/sql/create-database.js +39 -0
  522. package/src/database/drivers/mysql/sql/create-index.js +6 -0
  523. package/src/database/drivers/mysql/sql/create-table.js +6 -0
  524. package/src/database/drivers/mysql/sql/delete.js +21 -0
  525. package/src/database/drivers/mysql/sql/drop-database.js +6 -0
  526. package/src/database/drivers/mysql/sql/drop-table.js +6 -0
  527. package/src/database/drivers/mysql/sql/insert.js +6 -0
  528. package/src/database/drivers/mysql/sql/update.js +33 -0
  529. package/src/database/drivers/mysql/sql/upsert.js +13 -0
  530. package/src/database/drivers/mysql/structure-sql.js +93 -0
  531. package/src/database/drivers/mysql/table.js +121 -0
  532. package/src/database/drivers/pgsql/column.js +90 -0
  533. package/src/database/drivers/pgsql/columns-index.js +6 -0
  534. package/src/database/drivers/pgsql/foreign-key.js +12 -0
  535. package/src/database/drivers/pgsql/index.js +441 -0
  536. package/src/database/drivers/pgsql/options.js +32 -0
  537. package/src/database/drivers/pgsql/query-parser.js +6 -0
  538. package/src/database/drivers/pgsql/sql/alter-table.js +6 -0
  539. package/src/database/drivers/pgsql/sql/create-database.js +38 -0
  540. package/src/database/drivers/pgsql/sql/create-index.js +6 -0
  541. package/src/database/drivers/pgsql/sql/create-table.js +6 -0
  542. package/src/database/drivers/pgsql/sql/delete.js +21 -0
  543. package/src/database/drivers/pgsql/sql/drop-database.js +6 -0
  544. package/src/database/drivers/pgsql/sql/drop-table.js +6 -0
  545. package/src/database/drivers/pgsql/sql/insert.js +6 -0
  546. package/src/database/drivers/pgsql/sql/update.js +33 -0
  547. package/src/database/drivers/pgsql/sql/upsert.js +14 -0
  548. package/src/database/drivers/pgsql/structure-sql.js +126 -0
  549. package/src/database/drivers/pgsql/table.js +135 -0
  550. package/src/database/drivers/sqlite/base.js +509 -0
  551. package/src/database/drivers/sqlite/column.js +75 -0
  552. package/src/database/drivers/sqlite/columns-index.js +30 -0
  553. package/src/database/drivers/sqlite/connection-sql-js.js +46 -0
  554. package/src/database/drivers/sqlite/foreign-key.js +24 -0
  555. package/src/database/drivers/sqlite/index.js +394 -0
  556. package/src/database/drivers/sqlite/index.native.js +72 -0
  557. package/src/database/drivers/sqlite/index.web.js +99 -0
  558. package/src/database/drivers/sqlite/options.js +32 -0
  559. package/src/database/drivers/sqlite/query-parser.js +6 -0
  560. package/src/database/drivers/sqlite/query.js +35 -0
  561. package/src/database/drivers/sqlite/query.native.js +35 -0
  562. package/src/database/drivers/sqlite/query.web.js +49 -0
  563. package/src/database/drivers/sqlite/sql/alter-table.js +187 -0
  564. package/src/database/drivers/sqlite/sql/create-index.js +6 -0
  565. package/src/database/drivers/sqlite/sql/create-table.js +6 -0
  566. package/src/database/drivers/sqlite/sql/delete.js +26 -0
  567. package/src/database/drivers/sqlite/sql/drop-table.js +6 -0
  568. package/src/database/drivers/sqlite/sql/insert.js +6 -0
  569. package/src/database/drivers/sqlite/sql/update.js +33 -0
  570. package/src/database/drivers/sqlite/sql/upsert.js +14 -0
  571. package/src/database/drivers/sqlite/structure-sql.js +56 -0
  572. package/src/database/drivers/sqlite/table-rebuilder.js +96 -0
  573. package/src/database/drivers/sqlite/table.js +131 -0
  574. package/src/database/drivers/structure-sql/utils.js +35 -0
  575. package/src/database/handler.js +13 -0
  576. package/src/database/initializer-from-require-context.js +101 -0
  577. package/src/database/migration/index.js +438 -0
  578. package/src/database/migrator/files-finder.js +55 -0
  579. package/src/database/migrator/types.js +31 -0
  580. package/src/database/migrator.js +557 -0
  581. package/src/database/pool/async-tracked-multi-connection.js +1164 -0
  582. package/src/database/pool/base-methods-forward.js +52 -0
  583. package/src/database/pool/base.js +380 -0
  584. package/src/database/pool/single-multi-use.js +118 -0
  585. package/src/database/query/alter-table-base.js +104 -0
  586. package/src/database/query/base.js +49 -0
  587. package/src/database/query/create-database-base.js +42 -0
  588. package/src/database/query/create-index-base.js +117 -0
  589. package/src/database/query/create-table-base.js +205 -0
  590. package/src/database/query/delete-base.js +19 -0
  591. package/src/database/query/drop-database-base.js +38 -0
  592. package/src/database/query/drop-table-base.js +58 -0
  593. package/src/database/query/from-base.js +36 -0
  594. package/src/database/query/from-plain.js +16 -0
  595. package/src/database/query/from-table.js +18 -0
  596. package/src/database/query/index.js +533 -0
  597. package/src/database/query/insert-base.js +172 -0
  598. package/src/database/query/join-base.js +43 -0
  599. package/src/database/query/join-object.js +167 -0
  600. package/src/database/query/join-plain.js +18 -0
  601. package/src/database/query/join-tracker.js +93 -0
  602. package/src/database/query/model-class-query.js +1577 -0
  603. package/src/database/query/order-base.js +33 -0
  604. package/src/database/query/order-column.js +77 -0
  605. package/src/database/query/order-plain.js +28 -0
  606. package/src/database/query/preloader/belongs-to.js +267 -0
  607. package/src/database/query/preloader/ensure-model-class-initialized.js +18 -0
  608. package/src/database/query/preloader/has-many.js +316 -0
  609. package/src/database/query/preloader/has-one.js +123 -0
  610. package/src/database/query/preloader/selection.js +152 -0
  611. package/src/database/query/preloader.js +201 -0
  612. package/src/database/query/query-data.js +305 -0
  613. package/src/database/query/select-base.js +30 -0
  614. package/src/database/query/select-plain.js +18 -0
  615. package/src/database/query/select-table-and-column.js +28 -0
  616. package/src/database/query/update-base.js +41 -0
  617. package/src/database/query/upsert-base.js +103 -0
  618. package/src/database/query/where-base.js +38 -0
  619. package/src/database/query/where-combinator.js +31 -0
  620. package/src/database/query/where-hash.js +77 -0
  621. package/src/database/query/where-model-class-hash.js +505 -0
  622. package/src/database/query/where-not.js +23 -0
  623. package/src/database/query/where-plain.js +20 -0
  624. package/src/database/query/with-count.js +219 -0
  625. package/src/database/query-parser/base-query-parser.js +40 -0
  626. package/src/database/query-parser/from-parser.js +49 -0
  627. package/src/database/query-parser/group-parser.js +55 -0
  628. package/src/database/query-parser/joins-parser.js +37 -0
  629. package/src/database/query-parser/limit-parser.js +77 -0
  630. package/src/database/query-parser/options.js +94 -0
  631. package/src/database/query-parser/order-parser.js +45 -0
  632. package/src/database/query-parser/select-parser.js +67 -0
  633. package/src/database/query-parser/where-parser.js +46 -0
  634. package/src/database/record/acts-as-list.js +374 -0
  635. package/src/database/record/attachments/download.js +49 -0
  636. package/src/database/record/attachments/handle.js +188 -0
  637. package/src/database/record/attachments/normalize-input.js +213 -0
  638. package/src/database/record/attachments/storage-drivers/filesystem.js +114 -0
  639. package/src/database/record/attachments/storage-drivers/native.js +146 -0
  640. package/src/database/record/attachments/storage-drivers/s3.js +245 -0
  641. package/src/database/record/attachments/store.js +591 -0
  642. package/src/database/record/index.js +3970 -0
  643. package/src/database/record/instance-relationships/base.js +289 -0
  644. package/src/database/record/instance-relationships/belongs-to.js +84 -0
  645. package/src/database/record/instance-relationships/has-many.js +284 -0
  646. package/src/database/record/instance-relationships/has-one.js +117 -0
  647. package/src/database/record/record-not-found-error.js +3 -0
  648. package/src/database/record/relationships/base.js +195 -0
  649. package/src/database/record/relationships/belongs-to.js +57 -0
  650. package/src/database/record/relationships/has-many.js +46 -0
  651. package/src/database/record/relationships/has-one.js +46 -0
  652. package/src/database/record/state-machine.js +278 -0
  653. package/src/database/record/user-module.js +43 -0
  654. package/src/database/record/validators/base.js +27 -0
  655. package/src/database/record/validators/format.js +50 -0
  656. package/src/database/record/validators/presence.js +24 -0
  657. package/src/database/record/validators/uniqueness.js +124 -0
  658. package/src/database/table-data/index.js +241 -0
  659. package/src/database/table-data/table-column.js +416 -0
  660. package/src/database/table-data/table-foreign-key.js +69 -0
  661. package/src/database/table-data/table-index.js +46 -0
  662. package/src/database/table-data/table-reference.js +13 -0
  663. package/src/database/use-database.js +48 -0
  664. package/src/environment-handlers/base.js +561 -0
  665. package/src/environment-handlers/browser.js +338 -0
  666. package/src/environment-handlers/node/cli/commands/background-jobs-main.js +21 -0
  667. package/src/environment-handlers/node/cli/commands/background-jobs-runner.js +24 -0
  668. package/src/environment-handlers/node/cli/commands/background-jobs-worker.js +47 -0
  669. package/src/environment-handlers/node/cli/commands/beacon.js +21 -0
  670. package/src/environment-handlers/node/cli/commands/cli-command-context.js +31 -0
  671. package/src/environment-handlers/node/cli/commands/console.js +149 -0
  672. package/src/environment-handlers/node/cli/commands/db/schema/dump.js +43 -0
  673. package/src/environment-handlers/node/cli/commands/db/schema/load.js +69 -0
  674. package/src/environment-handlers/node/cli/commands/db/seed.js +79 -0
  675. package/src/environment-handlers/node/cli/commands/destroy/migration.js +47 -0
  676. package/src/environment-handlers/node/cli/commands/generate/base-models.js +367 -0
  677. package/src/environment-handlers/node/cli/commands/generate/frontend-models.js +872 -0
  678. package/src/environment-handlers/node/cli/commands/generate/migration.js +45 -0
  679. package/src/environment-handlers/node/cli/commands/generate/model.js +45 -0
  680. package/src/environment-handlers/node/cli/commands/init.js +68 -0
  681. package/src/environment-handlers/node/cli/commands/routes.js +63 -0
  682. package/src/environment-handlers/node/cli/commands/run-script.js +85 -0
  683. package/src/environment-handlers/node/cli/commands/runner.js +84 -0
  684. package/src/environment-handlers/node/cli/commands/server.js +151 -0
  685. package/src/environment-handlers/node/cli/commands/test.js +118 -0
  686. package/src/environment-handlers/node.js +887 -0
  687. package/src/error-logger.js +30 -0
  688. package/src/frontend-model-controller.js +3491 -0
  689. package/src/frontend-model-resource/base-resource.js +935 -0
  690. package/src/frontend-models/base.js +4004 -0
  691. package/src/frontend-models/clear-pending-debounced-callback.js +16 -0
  692. package/src/frontend-models/event-hook-models.js +49 -0
  693. package/src/frontend-models/model-registry.js +28 -0
  694. package/src/frontend-models/outgoing-event-buffer.js +51 -0
  695. package/src/frontend-models/preloader.js +169 -0
  696. package/src/frontend-models/query.js +2245 -0
  697. package/src/frontend-models/resource-config-validation.js +56 -0
  698. package/src/frontend-models/resource-definition.js +399 -0
  699. package/src/frontend-models/transport-serialization.js +369 -0
  700. package/src/frontend-models/use-created-event.js +21 -0
  701. package/src/frontend-models/use-destroyed-event.js +148 -0
  702. package/src/frontend-models/use-model-class-event.js +164 -0
  703. package/src/frontend-models/use-updated-event.js +152 -0
  704. package/src/frontend-models/websocket-channel.js +494 -0
  705. package/src/frontend-models/websocket-publishers.js +224 -0
  706. package/src/http-client/header.js +17 -0
  707. package/src/http-client/index.js +139 -0
  708. package/src/http-client/request.js +94 -0
  709. package/src/http-client/response.js +151 -0
  710. package/src/http-client/websocket-client.js +27 -0
  711. package/src/http-server/client/index.js +507 -0
  712. package/src/http-server/client/params-to-object.js +152 -0
  713. package/src/http-server/client/request-buffer/form-data-part.js +139 -0
  714. package/src/http-server/client/request-buffer/header.js +19 -0
  715. package/src/http-server/client/request-buffer/index.js +535 -0
  716. package/src/http-server/client/request-parser.js +195 -0
  717. package/src/http-server/client/request-runner.js +321 -0
  718. package/src/http-server/client/request-timing.js +171 -0
  719. package/src/http-server/client/request.js +114 -0
  720. package/src/http-server/client/response.js +251 -0
  721. package/src/http-server/client/uploaded-file/memory-uploaded-file.js +32 -0
  722. package/src/http-server/client/uploaded-file/temporary-uploaded-file.js +32 -0
  723. package/src/http-server/client/uploaded-file/uploaded-file.js +36 -0
  724. package/src/http-server/client/websocket-request.js +147 -0
  725. package/src/http-server/client/websocket-session.js +1755 -0
  726. package/src/http-server/cookie.js +245 -0
  727. package/src/http-server/development-reloader.js +240 -0
  728. package/src/http-server/index.js +561 -0
  729. package/src/http-server/remote-address.js +77 -0
  730. package/src/http-server/server-client.js +222 -0
  731. package/src/http-server/server-lock.js +178 -0
  732. package/src/http-server/websocket-channel-subscribers.js +110 -0
  733. package/src/http-server/websocket-channel.js +137 -0
  734. package/src/http-server/websocket-connection.js +118 -0
  735. package/src/http-server/websocket-event-log-store.js +433 -0
  736. package/src/http-server/websocket-events-host.js +170 -0
  737. package/src/http-server/websocket-events.js +50 -0
  738. package/src/http-server/worker-handler/channel-subscriber-dispatch.js +28 -0
  739. package/src/http-server/worker-handler/in-process.js +155 -0
  740. package/src/http-server/worker-handler/index.js +370 -0
  741. package/src/http-server/worker-handler/worker-script.js +6 -0
  742. package/src/http-server/worker-handler/worker-thread.js +286 -0
  743. package/src/initializer.js +39 -0
  744. package/src/jobs/.gitkeep +1 -0
  745. package/src/jobs/mail-delivery.js +22 -0
  746. package/src/logger/base-logger.js +34 -0
  747. package/src/logger/console-logger.js +28 -0
  748. package/src/logger/file-logger.js +36 -0
  749. package/src/logger/outputs/array-output.js +50 -0
  750. package/src/logger/outputs/console-output.js +32 -0
  751. package/src/logger/outputs/file-output.js +55 -0
  752. package/src/logger/outputs/stdout-output.js +64 -0
  753. package/src/logger.js +507 -0
  754. package/src/mailer/backends/smtp.js +197 -0
  755. package/src/mailer/base.js +337 -0
  756. package/src/mailer/delivery.js +70 -0
  757. package/src/mailer/index.js +24 -0
  758. package/src/mailer.js +15 -0
  759. package/src/plugins/sqljs-wasm-route-controller.js +70 -0
  760. package/src/plugins/sqljs-wasm-route.js +71 -0
  761. package/src/record-payload-values.js +83 -0
  762. package/src/routes/app-routes.js +17 -0
  763. package/src/routes/base-route.js +133 -0
  764. package/src/routes/basic-route.js +109 -0
  765. package/src/routes/built-in/debug/controller.js +12 -0
  766. package/src/routes/built-in/errors/controller.js +7 -0
  767. package/src/routes/built-in/errors/not-found.ejs +1 -0
  768. package/src/routes/get-route.js +75 -0
  769. package/src/routes/hooks/frontend-model-command-route-hook.js +100 -0
  770. package/src/routes/index.js +50 -0
  771. package/src/routes/namespace-route.js +51 -0
  772. package/src/routes/plugin-routes.js +141 -0
  773. package/src/routes/post-route.js +74 -0
  774. package/src/routes/resolver.js +535 -0
  775. package/src/routes/resource-route.js +154 -0
  776. package/src/routes/root-route.js +11 -0
  777. package/src/templates/configuration.js +61 -0
  778. package/src/templates/generate-migration.js +11 -0
  779. package/src/templates/generate-model.js +6 -0
  780. package/src/templates/routes.js +11 -0
  781. package/src/testing/base-expect.js +17 -0
  782. package/src/testing/browser-frontend-model-event-hook-scenarios.js +520 -0
  783. package/src/testing/browser-test-app.js +32 -0
  784. package/src/testing/expect-to-change.js +55 -0
  785. package/src/testing/expect-utils.js +269 -0
  786. package/src/testing/expect.js +763 -0
  787. package/src/testing/request-client.js +90 -0
  788. package/src/testing/test-files-finder.js +364 -0
  789. package/src/testing/test-filter-parser.js +198 -0
  790. package/src/testing/test-runner.js +1168 -0
  791. package/src/testing/test-suite-splitter.js +177 -0
  792. package/src/testing/test.js +370 -0
  793. package/src/types/external-modules.d.ts +57 -0
  794. package/src/utils/backtrace-cleaner-node.js +87 -0
  795. package/src/utils/backtrace-cleaner.js +266 -0
  796. package/src/utils/ensure-error.js +15 -0
  797. package/src/utils/event-emitter.js +8 -0
  798. package/src/utils/file-exists.js +18 -0
  799. package/src/utils/format-value.js +101 -0
  800. package/src/utils/model-scope.js +56 -0
  801. package/src/utils/nest-callbacks.js +22 -0
  802. package/src/utils/plain-object.js +14 -0
  803. package/src/utils/ransack.js +859 -0
  804. package/src/utils/rest-args-error.js +14 -0
  805. package/src/utils/singularize-model-name.js +18 -0
  806. package/src/utils/split-sql-statements.js +88 -0
  807. package/src/utils/to-import-specifier.js +53 -0
  808. package/src/utils/with-tracked-stack-async-hooks.js +103 -0
  809. package/src/utils/with-tracked-stack.js +38 -0
  810. package/src/velocious-error.js +34 -0
  811. package/tsconfig.json +16 -0
@@ -1,4 +1,5 @@
1
1
  // @ts-check
2
+
2
3
  /**
3
4
  * CreateIndexSqlArgs type.
4
5
  * @typedef {object} CreateIndexSqlArgs
@@ -51,6 +52,7 @@
51
52
  * @property {boolean} [processListComment] - Whether to add process-list comments to the query.
52
53
  * @property {string} [sourceStack] - Stack captured at the caller boundary.
53
54
  */
55
+
54
56
  /**
55
57
  * ActiveQueryDebugSnapshot type.
56
58
  * @typedef {object} ActiveQueryDebugSnapshot
@@ -60,6 +62,7 @@
60
62
  * @property {number} runningMs - Query runtime in milliseconds.
61
63
  * @property {string} sqlPreview - Truncated SQL preview.
62
64
  */
65
+
63
66
  /**
64
67
  * DatabaseConnectionDebugSnapshot type.
65
68
  * @typedef {object} DatabaseConnectionDebugSnapshot
@@ -72,6 +75,7 @@
72
75
  * @property {number} openTransactions - Number of open transaction frames.
73
76
  * @property {number} schemaCacheEntries - Number of cached schema metadata entries.
74
77
  */
78
+
75
79
  /**
76
80
  * ActiveQueryState type.
77
81
  * @typedef {object} ActiveQueryState
@@ -80,6 +84,7 @@
80
84
  * @property {number} startedAtUnixMs - Query start timestamp.
81
85
  * @property {string} sqlPreview - Truncated SQL preview.
82
86
  */
87
+
83
88
  /**
84
89
  * UpdateSqlArgsType type.
85
90
  * @typedef {object}UpdateSqlArgsType
@@ -95,1332 +100,1510 @@
95
100
  * @property {string} tableName - Table name to upsert into.
96
101
  * @property {string[]} updateColumns - Columns to update on conflict.
97
102
  */
98
- import BacktraceCleaner from "../../utils/backtrace-cleaner.js";
99
- import { getDatabaseAnnotations } from "../annotations.js";
100
- import Logger from "../../logger.js";
101
- import Query from "../query/index.js";
102
- import Handler from "../handler.js";
103
- import Mutex from "epic-locks/build/mutex.js";
104
- import strftime from "strftime";
105
- import UUID from "pure-uuid";
106
- import TableData from "../table-data/index.js";
107
- import TableColumn from "../table-data/table-column.js";
108
- import TableForeignKey from "../table-data/table-foreign-key.js";
109
- import wait from "awaitery/build/wait.js";
103
+
104
+ import BacktraceCleaner from "../../utils/backtrace-cleaner.js"
105
+ import { getDatabaseAnnotations } from "../annotations.js"
106
+ import Logger from "../../logger.js"
107
+ import Query from "../query/index.js"
108
+ import Handler from "../handler.js"
109
+ import Mutex from "epic-locks/build/mutex.js"
110
+ import strftime from "strftime"
111
+ import UUID from "pure-uuid"
112
+ import TableData from "../table-data/index.js"
113
+ import TableColumn from "../table-data/table-column.js"
114
+ import TableForeignKey from "../table-data/table-foreign-key.js"
115
+ import wait from "awaitery/build/wait.js"
116
+
110
117
  /**
111
118
  * Runs now ms.
112
119
  * @returns {number} - Current high-resolution-ish timestamp in milliseconds.
113
120
  */
114
121
  function nowMs() {
115
- if (globalThis.performance && typeof globalThis.performance.now == "function") {
116
- return globalThis.performance.now();
117
- }
118
- return Date.now();
122
+ if (globalThis.performance && typeof globalThis.performance.now == "function") {
123
+ return globalThis.performance.now()
124
+ }
125
+
126
+ return Date.now()
119
127
  }
128
+
120
129
  /**
121
130
  * Runs format elapsed ms.
122
131
  * @param {number} elapsedMs - Elapsed milliseconds.
123
132
  * @returns {string} - Formatted elapsed milliseconds.
124
133
  */
125
134
  function formatElapsedMs(elapsedMs) {
126
- return `${Math.max(elapsedMs, 0).toFixed(1)}ms`;
135
+ return `${Math.max(elapsedMs, 0).toFixed(1)}ms`
127
136
  }
137
+
128
138
  export default class VelociousDatabaseDriversBase {
129
- /**
130
- * Id seq.
131
- @type {number | undefined} */
132
- idSeq = undefined;
133
- /**
134
- * Narrows the runtime value to the documented type.
135
- @type {Array<Array<() => void | Promise<void>>>} */
136
- _afterCommitCallbackFrames;
137
- /**
138
- * Narrows the runtime value to the documented type.
139
- @type {Map<string, Promise<?>>} */
140
- _schemaCache;
141
- /**
142
- * Narrows the runtime value to the documented type.
143
- @type {(() => void) | undefined} */
144
- _schemaCacheInvalidator;
145
- /**
146
- * Narrows the runtime value to the documented type.
147
- @type {string | undefined} */
148
- _connectionCheckoutName;
149
- /**
150
- * Active query.
151
- @type {ActiveQueryState | null} */
152
- _activeQuery = null;
153
- /**
154
- * Runs constructor.
155
- * @param {import("../../configuration-types.js").DatabaseConfigurationType} config - Configuration object.
156
- * @param {import("../../configuration.js").default} configuration - Configuration instance.
157
- */
158
- constructor(config, configuration) {
159
- this._args = config;
160
- this.configuration = configuration;
161
- this.mutex = new Mutex(); // Can be used to lock this instance for exclusive use
162
- this.logger = new Logger(this);
163
- this._afterCommitCallbackFrames = [];
164
- this._transactionsCount = 0;
165
- this._transactionsActionsMutex = new Mutex();
166
- this._schemaCache = new Map();
167
- }
168
- /**
169
- * Runs add foreign key.
170
- * @param {string} tableName - Table name.
171
- * @param {string} columnName - Column name.
172
- * @param {string} referencedTableName - Referenced table name.
173
- * @param {string} referencedColumnName - Referenced column name.
174
- * @param {object} args - Options object.
175
- * @returns {Promise<void>} - Resolves when complete.
176
- */
177
- async addForeignKey(tableName, columnName, referencedTableName, referencedColumnName, args) {
178
- this._assertNotReadOnly();
179
- const tableForeignKeyArgs = Object.assign({
180
- columnName,
181
- tableName,
182
- referencedColumnName,
183
- referencedTableName
184
- }, args);
185
- const tableForeignKey = new TableForeignKey(tableForeignKeyArgs);
186
- const tableData = new TableData(tableName);
187
- tableData.addForeignKey(tableForeignKey);
188
- const alterTableSQLs = await this.alterTableSQLs(tableData);
189
- for (const alterTableSQL of alterTableSQLs) {
190
- await this.query(alterTableSQL);
191
- }
192
- }
193
- /**
194
- * Runs alter table sqls.
195
- * @abstract
196
- * @param {import("../table-data/index.js").default} _tableData - Table data.
197
- * @returns {Promise<string[]>} - Resolves with SQL statements.
198
- */
199
- alterTableSQLs(_tableData) {
200
- throw new Error("alterTableSQLs not implemented");
201
- }
202
- /**
203
- * Runs connect.
204
- * @abstract
205
- * @returns {Promise<void>} - Resolves when complete.
206
- */
207
- connect() {
208
- throw new Error("'connect' not implemented");
209
- }
210
- /**
211
- * Optional close hook for database drivers.
212
- * @returns {Promise<void>} - Resolves when complete.
213
- */
214
- async close() {
215
- // No-op by default
216
- }
217
- /**
218
- * Runs set connection checkout name.
219
- * @param {string | undefined} name - Human-readable name for this active checkout.
220
- * @returns {Promise<void>} - Resolves when complete.
221
- */
222
- async setConnectionCheckoutName(name) {
223
- this._connectionCheckoutName = name;
224
- this._connectionCheckedOutAtUnixMs = Date.now();
225
- }
226
- /**
227
- * Runs clear connection checkout name.
228
- * @returns {Promise<void>} - Resolves when complete.
229
- */
230
- async clearConnectionCheckoutName() {
231
- this._connectionCheckoutName = undefined;
232
- this._connectionCheckedOutAtUnixMs = undefined;
233
- }
234
- /**
235
- * Runs reconnect.
236
- * @returns {Promise<void>} - Resolves when complete.
237
- */
238
- async reconnect() {
239
- this.clearSchemaCache();
240
- await this.close();
241
- await this.connect();
242
- }
243
- /**
244
- * Runs create database sql.
245
- * @abstract
246
- * @param {string} databaseName - Database name.
247
- * @param {object} [args] - Options object.
248
- * @param {boolean} [args.ifNotExists] - Whether if not exists.
249
- * @param {string} [args.databaseCharset] - Database-default character set (driver-specific; mysql/mariadb).
250
- * @param {string} [args.databaseCollation] - Database-default collation (driver-specific; mysql/mariadb).
251
- * @returns {string[]} - SQL statements.
252
- */
253
- createDatabaseSql(databaseName, args) { throw new Error("'createDatabaseSql' not implemented"); } // eslint-disable-line no-unused-vars
254
- /**
255
- * Runs drop database sql.
256
- * @abstract
257
- * @param {string} databaseName - Database name.
258
- * @param {object} [args] - Options object.
259
- * @param {boolean} [args.ifExists] - Whether if exists.
260
- * @returns {string[]} - SQL statements.
261
- */
262
- dropDatabaseSql(databaseName, args) { throw new Error("'dropDatabaseSql' not implemented"); } // eslint-disable-line no-unused-vars
263
- /**
264
- * Runs create index sqls.
265
- * @abstract
266
- * @param {CreateIndexSqlArgs} indexData - Index data.
267
- * @returns {Promise<string[]>} - Resolves with SQL statements.
268
- */
269
- async createIndexSQLs(indexData) {
270
- throw new Error("'createIndexSQLs' not implemented");
271
- }
272
- /**
273
- * Runs create table.
274
- * @param {import("../table-data/index.js").default} tableData - Table data.
275
- * @returns {Promise<void>} - Resolves when complete.
276
- */
277
- async createTable(tableData) {
278
- this._assertNotReadOnly();
279
- const sqls = await this.createTableSql(tableData);
280
- for (const sql of sqls) {
281
- await this.query(sql);
282
- }
283
- }
284
- /**
285
- * Runs create table sql.
286
- * @abstract
287
- * @param {import("../table-data/index.js").default} tableData - Table data.
288
- * @returns {Promise<string[]>} - Resolves with SQL statements.
289
- */
290
- async createTableSql(tableData) {
291
- throw new Error("'createTableSql' not implemented");
292
- }
293
- /**
294
- * Runs delete.
295
- * @param {DeleteSqlArgsType} args - Options object.
296
- * @returns {Promise<void>} - Resolves when complete.
297
- */
298
- async delete(args) {
299
- this._assertNotReadOnly();
300
- const sql = this.deleteSql(args);
301
- await this.query(sql);
302
- }
303
- /**
304
- * Runs delete sql.
305
- * @abstract
306
- * @param {DeleteSqlArgsType} args - Options object.
307
- * @returns {string} - SQL string.
308
- */
309
- deleteSql(args) {
310
- throw new Error(`'deleteSql' not implemented`);
311
- }
312
- /**
313
- * Runs drop table.
314
- * @param {string} tableName - Table name.
315
- * @param {DropTableSqlArgsType} [args] - Options object.
316
- * @returns {Promise<void>} - Resolves when complete.
317
- */
318
- async dropTable(tableName, args) {
319
- this._assertNotReadOnly();
320
- const sqls = await this.dropTableSQLs(tableName, args);
321
- for (const sql of sqls) {
322
- await this.query(sql);
323
- }
324
- }
325
- /**
326
- * Runs drop table sqls.
327
- * @abstract
328
- * @param {string} tableName - Table name.
329
- * @param {DropTableSqlArgsType} [args] - Options object.
330
- * @returns {Promise<string[]>} - Resolves with SQL statements.
331
- */
332
- async dropTableSQLs(tableName, args) {
333
- throw new Error("dropTableSQLs not implemented");
334
- }
335
- /**
336
- * Runs escape.
337
- * @abstract
338
- * @param {?} value - Value to use.
339
- * @returns {?} - The escape.
340
- */
341
- escape(value) {
342
- throw new Error("'escape' not implemented");
343
- }
344
- /**
345
- * Runs get args.
346
- * @returns {import("../../configuration-types.js").DatabaseConfigurationType} - The args.
347
- */
348
- getArgs() {
349
- return this._args;
350
- }
351
- /**
352
- * Runs get configuration.
353
- * @returns {import("../../configuration.js").default} - The configuration.
354
- */
355
- getConfiguration() {
356
- if (!this.configuration)
357
- throw new Error("No configuration set");
358
- return this.configuration;
359
- }
360
- /**
361
- * Runs get id seq.
362
- * @returns {number | undefined} - The id seq.
363
- */
364
- getIdSeq() {
365
- return this.idSeq;
366
- }
367
- /**
368
- * Clears cached schema metadata for this driver instance.
369
- * @returns {void} - No return value.
370
- */
371
- clearSchemaCache() {
372
- if (this._schemaCacheInvalidator) {
373
- this._schemaCacheInvalidator();
374
- return;
375
- }
376
- this._clearLocalSchemaCache();
377
- }
378
- /**
379
- * Clears only the metadata cached on this driver instance.
380
- * @returns {void} - No return value.
381
- */
382
- _clearLocalSchemaCache() {
383
- this._schemaCache.clear();
384
- }
385
- /**
386
- * Runs set schema cache invalidator.
387
- * @param {() => void} invalidator - Callback used to clear schema caches that share this driver pool.
388
- * @returns {void} - No return value.
389
- */
390
- setSchemaCacheInvalidator(invalidator) {
391
- this._schemaCacheInvalidator = invalidator;
392
- }
393
- /**
394
- * Runs schema cache enabled.
395
- * @returns {boolean} - Whether schema metadata caching is enabled.
396
- */
397
- _schemaCacheEnabled() {
398
- return this.getArgs().schemaCache !== false;
399
- }
400
- /**
401
- * Runs cached schema metadata.
402
- * @template T
403
- * @param {string} cacheKey - Schema cache key.
404
- * @param {() => Promise<T>} callback - Cache miss callback.
405
- * @returns {Promise<T>} - Resolves with the cached metadata.
406
- */
407
- async _cachedSchemaMetadata(cacheKey, callback) {
408
- if (!this._schemaCacheEnabled())
409
- return await callback();
410
- const existingPromise = this._schemaCache.get(cacheKey);
411
- if (existingPromise) {
412
- return /** Narrows the runtime value to the documented type. @type {T} */ (this._schemaCacheReturnValue(await existingPromise));
413
- }
414
- const promise = (async () => await callback())();
415
- this._schemaCache.set(cacheKey, promise);
416
- try {
417
- return /** Narrows the runtime value to the documented type. @type {T} */ (this._schemaCacheReturnValue(await promise));
418
- }
419
- catch (error) {
420
- if (this._schemaCache.get(cacheKey) === promise) {
421
- this._schemaCache.delete(cacheKey);
422
- }
423
- throw error;
424
- }
425
- }
426
- /**
427
- * Runs cached table schema metadata.
428
- * @template T
429
- * @param {string} tableName - Table name.
430
- * @param {string} metadataName - Metadata name.
431
- * @param {() => Promise<T>} callback - Cache miss callback.
432
- * @returns {Promise<T>} - Resolves with the cached table metadata.
433
- */
434
- async _cachedTableSchemaMetadata(tableName, metadataName, callback) {
435
- return await this._cachedSchemaMetadata(`table:${tableName}:${metadataName}`, callback);
436
- }
437
- /**
438
- * Runs schema cache return value.
439
- * @param {?} value - Cached value.
440
- * @returns {?} - Value returned to callers.
441
- */
442
- _schemaCacheReturnValue(value) {
443
- if (Array.isArray(value))
444
- return value.slice();
445
- return value;
446
- }
447
- /**
448
- * Runs get tables.
449
- * @abstract
450
- * @returns {Promise<Array<import("./base-table.js").default>>} - Resolves with the tables.
451
- */
452
- getTables() {
453
- throw new Error(`${this.constructor.name}#getTables not implemented`);
454
- }
455
- /**
456
- * Runs structure sql.
457
- * @returns {Promise<string | null>} - Resolves with SQL string.
458
- */
459
- async structureSql() {
460
- return null;
461
- }
462
- /**
463
- * Runs get table by name.
464
- * @param {string} name - Name.
465
- * @param {object} [args] - Options object.
466
- * @param {boolean} args.throwError - Whether throw error.
467
- * @returns {Promise<import("./base-table.js").default | undefined>} - Resolves with the table by name.
468
- */
469
- async getTableByName(name, args) {
470
- const tables = await this.getTables();
471
- const tableNames = [];
472
- let table;
473
- for (const candidate of tables) {
474
- const candidateName = candidate.getName();
475
- if (candidateName == name) {
476
- table = candidate;
477
- break;
478
- }
479
- tableNames.push(candidateName);
480
- }
481
- if (!table && args?.throwError !== false) {
482
- throw new Error(this._missingTableErrorMessage(name, tableNames));
483
- }
484
- return table;
485
- }
486
- /**
487
- * Runs missing table error message.
488
- * @param {string} name - Table name.
489
- * @param {string[]} tableNames - Available table names.
490
- * @returns {string} - Error message.
491
- */
492
- _missingTableErrorMessage(name, tableNames) {
493
- const environment = this.getConfiguration().getEnvironment();
494
- const args = this.getArgs();
495
- const databaseName = args?.database || args?.name || args?.useDatabase || "unknown";
496
- return `Couldn't find a table by that name "${name}" in: ${tableNames.join(", ")} (environment: ${environment}, database: ${databaseName})`;
497
- }
498
- /**
499
- * Runs get table by name or fail.
500
- * @param {string} name - Name.
501
- * @returns {Promise<import("./base-table.js").default>} - Resolves with the table by name or fail.
502
- */
503
- async getTableByNameOrFail(name) {
504
- return /** Narrows the runtime value to the documented type. @type {import("./base-table.js").default} */ (await this.getTableByName(name, { throwError: true }));
505
- }
506
- /**
507
- * Runs get type.
508
- * @abstract
509
- * @returns {string} - The type.
510
- */
511
- getType() {
512
- throw new Error("'type' not implemented");
513
- }
514
- /**
515
- * Runs insert.
516
- * @param {InsertSqlArgsType} args - Options object.
517
- * @returns {Promise<void>} - Resolves when complete.
518
- */
519
- async insert(args) {
520
- this._assertNotReadOnly();
521
- const sql = this.insertSql(args);
522
- await this.query(sql);
523
- }
524
- /**
525
- * Runs insert multiple.
526
- * @param {string} tableName - Table name.
527
- * @param {Array<string>} columns - Column names.
528
- * @param {Array<Array<?>>} rows - Rows to insert.
529
- * @returns {Promise<void>} - Resolves when complete.
530
- */
531
- async insertMultiple(tableName, columns, rows) {
532
- this._assertNotReadOnly();
533
- const sql = this.insertSql({ columns, tableName, rows });
534
- await this.query(sql);
535
- }
536
- /**
537
- * Runs insert sql.
538
- * @abstract
539
- * @param {InsertSqlArgsType} args - Options object.
540
- * @returns {string} - SQL string.
541
- */
542
- insertSql(args) {
543
- throw new Error("'insertSql' not implemented");
544
- }
545
- /**
546
- * Runs upsert.
547
- * @param {UpsertSqlArgsType} args - Options object.
548
- * @returns {Promise<void>} - Resolves when complete.
549
- */
550
- async upsert(args) {
551
- this._assertNotReadOnly();
552
- const sql = this.upsertSql(args);
553
- await this.query(sql);
554
- }
555
- /**
556
- * Runs last insert id.
557
- * @abstract
558
- * @returns {Promise<number>} - Resolves with the last insert id.
559
- */
560
- lastInsertID() {
561
- throw new Error(`${this.constructor.name}#lastInsertID not implemented`);
562
- }
563
- /**
564
- * Runs convert value.
565
- * @param {?} value - Value to use.
566
- * @returns {?} - The convert value.
567
- */
568
- _convertValue(value) {
569
- if (typeof value === "boolean") {
570
- return value ? 1 : 0;
571
- }
572
- if (value instanceof Date) {
573
- return strftime("%F %T.%L", value);
574
- }
575
- // JSON-encode plain objects/arrays so they land in JSON/text columns as valid
576
- // JSON. Without this, drivers like mysql's escape() turn an object into
577
- // `key` = value assignment pairs (its `SET ?` form), producing invalid SQL in
578
- // a value position. Only PLAIN objects and arrays are encoded — class
579
- // instances (e.g. model records, which are circular via _changes) and Buffers
580
- // pass through untouched, since JSON.stringify on a record throws on its
581
- // circular structure and a record is never a valid column value to serialize.
582
- if (this._isJsonEncodableValue(value)) {
583
- return JSON.stringify(value);
584
- }
585
- return value;
586
- }
587
- /**
588
- * Whether a value is a plain object or array that should be JSON-encoded for a
589
- * JSON/text column. Excludes Buffers and class instances (e.g. model records).
590
- * @param {?} value - Value to test.
591
- * @returns {boolean} - Whether to JSON-encode the value.
592
- */
593
- _isJsonEncodableValue(value) {
594
- if (value === null || typeof value !== "object")
595
- return false;
596
- if (typeof Buffer !== "undefined" && Buffer.isBuffer(value))
597
- return false;
598
- if (Array.isArray(value))
599
- return true;
600
- const prototype = Object.getPrototypeOf(value);
601
- return prototype === Object.prototype || prototype === null;
602
- }
603
- /**
604
- * Runs options.
605
- * @abstract
606
- * @returns {import("../query-parser/options.js").default} - The options options.
607
- */
608
- options() {
609
- throw new Error("'options' not implemented.");
610
- }
611
- /**
612
- * Runs quote.
613
- * @param {?} value - Value to use.
614
- * @returns {number | string} - The quote.
615
- */
616
- quote(value) {
617
- if (typeof value == "number")
618
- return value;
619
- const escapedValue = this.escape(value);
620
- const result = `"${escapedValue}"`;
621
- return result;
622
- }
623
- /**
624
- * Runs quote column.
625
- * @param {string} columnName - Column name.
626
- * @returns {string} - The quote column.
627
- */
628
- quoteColumn(columnName) {
629
- return this.options().quoteColumnName(columnName);
630
- }
631
- /**
632
- * Runs quote index.
633
- * @param {string} columnName - Column name.
634
- * @returns {string} - The quote index.
635
- */
636
- quoteIndex(columnName) {
637
- return this.options().quoteIndexName(columnName);
638
- }
639
- /**
640
- * Runs quote table.
641
- * @param {string} tableName - Table name.
642
- * @returns {string} - The quote table.
643
- */
644
- quoteTable(tableName) {
645
- return this.options().quoteTableName(tableName);
646
- }
647
- /**
648
- * Runs new query.
649
- * @returns {Query} - The new query.
650
- */
651
- newQuery() {
652
- const handler = new Handler();
653
- return new Query({
654
- driver: this,
655
- handler
656
- });
657
- }
658
- /**
659
- * Runs select.
660
- * @param {string} tableName - Table name.
661
- * @returns {Promise<QueryResultType>} - Resolves with the select.
662
- */
663
- async select(tableName) {
664
- const query = this.newQuery();
665
- const sql = query
666
- .from(tableName)
667
- .toSql();
668
- return await this.query(sql);
669
- }
670
- /**
671
- * Runs set id seq.
672
- * @param {number | undefined} newIdSeq - New id seq.
673
- * @returns {void} - No return value.
674
- */
675
- setIdSeq(newIdSeq) {
676
- this.idSeq = newIdSeq;
677
- }
678
- /**
679
- * Runs should set auto increment when primary key.
680
- * @abstract
681
- * @returns {boolean} - Whether set auto increment when primary key.
682
- */
683
- shouldSetAutoIncrementWhenPrimaryKey() {
684
- throw new Error(`'shouldSetAutoIncrementWhenPrimaryKey' not implemented`);
685
- }
686
- /**
687
- * Runs supports default primary key uuid.
688
- * @returns {boolean} - Whether supports default primary key uuid.
689
- */
690
- supportsDefaultPrimaryKeyUUID() { return false; }
691
- /**
692
- * Runs supports insert into returning.
693
- * @abstract
694
- * @returns {boolean} - Whether supports insert into returning.
695
- */
696
- supportsInsertIntoReturning() { return false; }
697
- /**
698
- * Runs table exists.
699
- * @param {string} tableName - Table name.
700
- * @returns {Promise<boolean>} - Resolves with Whether table exists.
701
- */
702
- async tableExists(tableName) {
703
- const tables = await this.getTables();
704
- const table = tables.find((table) => table.getName() == tableName);
705
- if (table)
706
- return true;
707
- return false;
708
- }
709
- /**
710
- * Runs transaction.
711
- * @param {() => Promise<void>} callback - Callback function.
712
- * @returns {Promise<?>} - Resolves with the transaction.
713
- */
714
- async transaction(callback) {
715
- const savePointName = this.generateSavePointName();
716
- /**
717
- * Callback frame.
718
- @type {Array<() => void | Promise<void>>} */
719
- const callbackFrame = [];
720
- let transactionStarted = false;
721
- let savePointStarted = false;
722
- this._afterCommitCallbackFrames.push(callbackFrame);
723
- if (this._transactionsCount == 0) {
724
- this.logger.debug("Start transaction");
725
- await this.startTransaction();
726
- transactionStarted = true;
727
- }
728
- else {
729
- this.logger.debug("Start savepoint", savePointName);
730
- await this.startSavePoint(savePointName);
731
- savePointStarted = true;
732
- }
733
- let result;
139
+ /**
140
+ * Id seq.
141
+ @type {number | undefined} */
142
+ idSeq = undefined
143
+ /**
144
+ * Narrows the runtime value to the documented type.
145
+ @type {Array<Array<() => void | Promise<void>>>} */
146
+ _afterCommitCallbackFrames
147
+ /**
148
+ * Narrows the runtime value to the documented type.
149
+ @type {Map<string, Promise<?>>} */
150
+ _schemaCache
151
+ /**
152
+ * Narrows the runtime value to the documented type.
153
+ @type {(() => void) | undefined} */
154
+ _schemaCacheInvalidator
155
+ /**
156
+ * Narrows the runtime value to the documented type.
157
+ @type {string | undefined} */
158
+ _connectionCheckoutName
159
+ /**
160
+ * Active query.
161
+ @type {ActiveQueryState | null} */
162
+ _activeQuery = null
163
+
164
+ /**
165
+ * Runs constructor.
166
+ * @param {import("../../configuration-types.js").DatabaseConfigurationType} config - Configuration object.
167
+ * @param {import("../../configuration.js").default} configuration - Configuration instance.
168
+ */
169
+ constructor(config, configuration) {
170
+ this._args = config
171
+ this.configuration = configuration
172
+ this.mutex = new Mutex() // Can be used to lock this instance for exclusive use
173
+ this.logger = new Logger(this)
174
+ this._afterCommitCallbackFrames = []
175
+ this._transactionsCount = 0
176
+ this._transactionsActionsMutex = new Mutex()
177
+ this._schemaCache = new Map()
178
+ }
179
+
180
+ /**
181
+ * Runs add foreign key.
182
+ * @param {string} tableName - Table name.
183
+ * @param {string} columnName - Column name.
184
+ * @param {string} referencedTableName - Referenced table name.
185
+ * @param {string} referencedColumnName - Referenced column name.
186
+ * @param {object} args - Options object.
187
+ * @returns {Promise<void>} - Resolves when complete.
188
+ */
189
+ async addForeignKey(tableName, columnName, referencedTableName, referencedColumnName, args) {
190
+ this._assertNotReadOnly()
191
+ const tableForeignKeyArgs = Object.assign(
192
+ {
193
+ columnName,
194
+ tableName,
195
+ referencedColumnName,
196
+ referencedTableName
197
+ },
198
+ args
199
+ )
200
+ const tableForeignKey = new TableForeignKey(tableForeignKeyArgs)
201
+ const tableData = new TableData(tableName)
202
+
203
+ tableData.addForeignKey(tableForeignKey)
204
+
205
+ const alterTableSQLs = await this.alterTableSQLs(tableData)
206
+
207
+ for (const alterTableSQL of alterTableSQLs) {
208
+ await this.query(alterTableSQL)
209
+ }
210
+ }
211
+
212
+ /**
213
+ * Runs alter table sqls.
214
+ * @abstract
215
+ * @param {import("../table-data/index.js").default} _tableData - Table data.
216
+ * @returns {Promise<string[]>} - Resolves with SQL statements.
217
+ */
218
+ alterTableSQLs(_tableData) {
219
+ throw new Error("alterTableSQLs not implemented")
220
+ }
221
+
222
+ /**
223
+ * Runs connect.
224
+ * @abstract
225
+ * @returns {Promise<void>} - Resolves when complete.
226
+ */
227
+ connect() {
228
+ throw new Error("'connect' not implemented")
229
+ }
230
+
231
+ /**
232
+ * Optional close hook for database drivers.
233
+ * @returns {Promise<void>} - Resolves when complete.
234
+ */
235
+ async close() {
236
+ // No-op by default
237
+ }
238
+
239
+ /**
240
+ * Runs set connection checkout name.
241
+ * @param {string | undefined} name - Human-readable name for this active checkout.
242
+ * @returns {Promise<void>} - Resolves when complete.
243
+ */
244
+ async setConnectionCheckoutName(name) {
245
+ this._connectionCheckoutName = name
246
+ this._connectionCheckedOutAtUnixMs = Date.now()
247
+ }
248
+
249
+ /**
250
+ * Runs clear connection checkout name.
251
+ * @returns {Promise<void>} - Resolves when complete.
252
+ */
253
+ async clearConnectionCheckoutName() {
254
+ this._connectionCheckoutName = undefined
255
+ this._connectionCheckedOutAtUnixMs = undefined
256
+ }
257
+
258
+ /**
259
+ * Runs reconnect.
260
+ * @returns {Promise<void>} - Resolves when complete.
261
+ */
262
+ async reconnect() {
263
+ this.clearSchemaCache()
264
+ await this.close()
265
+ await this.connect()
266
+ }
267
+
268
+ /**
269
+ * Runs create database sql.
270
+ * @abstract
271
+ * @param {string} databaseName - Database name.
272
+ * @param {object} [args] - Options object.
273
+ * @param {boolean} [args.ifNotExists] - Whether if not exists.
274
+ * @param {string} [args.databaseCharset] - Database-default character set (driver-specific; mysql/mariadb).
275
+ * @param {string} [args.databaseCollation] - Database-default collation (driver-specific; mysql/mariadb).
276
+ * @returns {string[]} - SQL statements.
277
+ */
278
+ createDatabaseSql(databaseName, args) { throw new Error("'createDatabaseSql' not implemented") } // eslint-disable-line no-unused-vars
279
+
280
+ /**
281
+ * Runs drop database sql.
282
+ * @abstract
283
+ * @param {string} databaseName - Database name.
284
+ * @param {object} [args] - Options object.
285
+ * @param {boolean} [args.ifExists] - Whether if exists.
286
+ * @returns {string[]} - SQL statements.
287
+ */
288
+ dropDatabaseSql(databaseName, args) { throw new Error("'dropDatabaseSql' not implemented") } // eslint-disable-line no-unused-vars
289
+
290
+ /**
291
+ * Runs create index sqls.
292
+ * @abstract
293
+ * @param {CreateIndexSqlArgs} indexData - Index data.
294
+ * @returns {Promise<string[]>} - Resolves with SQL statements.
295
+ */
296
+ async createIndexSQLs(indexData) { // eslint-disable-line no-unused-vars
297
+ throw new Error("'createIndexSQLs' not implemented")
298
+ }
299
+
300
+ /**
301
+ * Runs create table.
302
+ * @param {import("../table-data/index.js").default} tableData - Table data.
303
+ * @returns {Promise<void>} - Resolves when complete.
304
+ */
305
+ async createTable(tableData) {
306
+ this._assertNotReadOnly()
307
+ const sqls = await this.createTableSql(tableData)
308
+
309
+ for (const sql of sqls) {
310
+ await this.query(sql)
311
+ }
312
+ }
313
+
314
+ /**
315
+ * Runs create table sql.
316
+ * @abstract
317
+ * @param {import("../table-data/index.js").default} tableData - Table data.
318
+ * @returns {Promise<string[]>} - Resolves with SQL statements.
319
+ */
320
+ async createTableSql(tableData) { // eslint-disable-line no-unused-vars
321
+ throw new Error("'createTableSql' not implemented")
322
+ }
323
+
324
+ /**
325
+ * Runs delete.
326
+ * @param {DeleteSqlArgsType} args - Options object.
327
+ * @returns {Promise<void>} - Resolves when complete.
328
+ */
329
+ async delete(args) {
330
+ this._assertNotReadOnly()
331
+ const sql = this.deleteSql(args)
332
+
333
+ await this.query(sql)
334
+ }
335
+
336
+ /**
337
+ * Runs delete sql.
338
+ * @abstract
339
+ * @param {DeleteSqlArgsType} args - Options object.
340
+ * @returns {string} - SQL string.
341
+ */
342
+ deleteSql(args) { // eslint-disable-line no-unused-vars
343
+ throw new Error(`'deleteSql' not implemented`)
344
+ }
345
+
346
+ /**
347
+ * Runs drop table.
348
+ * @param {string} tableName - Table name.
349
+ * @param {DropTableSqlArgsType} [args] - Options object.
350
+ * @returns {Promise<void>} - Resolves when complete.
351
+ */
352
+ async dropTable(tableName, args) {
353
+ this._assertNotReadOnly()
354
+ const sqls = await this.dropTableSQLs(tableName, args)
355
+
356
+ for (const sql of sqls) {
357
+ await this.query(sql)
358
+ }
359
+ }
360
+
361
+ /**
362
+ * Runs drop table sqls.
363
+ * @abstract
364
+ * @param {string} tableName - Table name.
365
+ * @param {DropTableSqlArgsType} [args] - Options object.
366
+ * @returns {Promise<string[]>} - Resolves with SQL statements.
367
+ */
368
+ async dropTableSQLs(tableName, args) { // eslint-disable-line no-unused-vars
369
+ throw new Error("dropTableSQLs not implemented")
370
+ }
371
+
372
+ /**
373
+ * Runs escape.
374
+ * @abstract
375
+ * @param {?} value - Value to use.
376
+ * @returns {?} - The escape.
377
+ */
378
+ escape(value) { // eslint-disable-line no-unused-vars
379
+ throw new Error("'escape' not implemented")
380
+ }
381
+
382
+ /**
383
+ * Runs get args.
384
+ * @returns {import("../../configuration-types.js").DatabaseConfigurationType} - The args.
385
+ */
386
+ getArgs() {
387
+ return this._args
388
+ }
389
+
390
+ /**
391
+ * Runs get configuration.
392
+ * @returns {import("../../configuration.js").default} - The configuration.
393
+ */
394
+ getConfiguration() {
395
+ if (!this.configuration) throw new Error("No configuration set")
396
+
397
+ return this.configuration
398
+ }
399
+
400
+ /**
401
+ * Runs get id seq.
402
+ * @returns {number | undefined} - The id seq.
403
+ */
404
+ getIdSeq() {
405
+ return this.idSeq
406
+ }
407
+
408
+ /**
409
+ * Clears cached schema metadata for this driver instance.
410
+ * @returns {void} - No return value.
411
+ */
412
+ clearSchemaCache() {
413
+ if (this._schemaCacheInvalidator) {
414
+ this._schemaCacheInvalidator()
415
+ return
416
+ }
417
+
418
+ this._clearLocalSchemaCache()
419
+ }
420
+
421
+ /**
422
+ * Clears only the metadata cached on this driver instance.
423
+ * @returns {void} - No return value.
424
+ */
425
+ _clearLocalSchemaCache() {
426
+ this._schemaCache.clear()
427
+ }
428
+
429
+ /**
430
+ * Runs set schema cache invalidator.
431
+ * @param {() => void} invalidator - Callback used to clear schema caches that share this driver pool.
432
+ * @returns {void} - No return value.
433
+ */
434
+ setSchemaCacheInvalidator(invalidator) {
435
+ this._schemaCacheInvalidator = invalidator
436
+ }
437
+
438
+ /**
439
+ * Runs schema cache enabled.
440
+ * @returns {boolean} - Whether schema metadata caching is enabled.
441
+ */
442
+ _schemaCacheEnabled() {
443
+ return this.getArgs().schemaCache !== false
444
+ }
445
+
446
+ /**
447
+ * Runs cached schema metadata.
448
+ * @template T
449
+ * @param {string} cacheKey - Schema cache key.
450
+ * @param {() => Promise<T>} callback - Cache miss callback.
451
+ * @returns {Promise<T>} - Resolves with the cached metadata.
452
+ */
453
+ async _cachedSchemaMetadata(cacheKey, callback) {
454
+ if (!this._schemaCacheEnabled()) return await callback()
455
+
456
+ const existingPromise = this._schemaCache.get(cacheKey)
457
+
458
+ if (existingPromise) {
459
+ return /** Narrows the runtime value to the documented type. @type {T} */ (this._schemaCacheReturnValue(await existingPromise))
460
+ }
461
+
462
+ const promise = (async () => await callback())()
463
+
464
+ this._schemaCache.set(cacheKey, promise)
465
+
466
+ try {
467
+ return /** Narrows the runtime value to the documented type. @type {T} */ (this._schemaCacheReturnValue(await promise))
468
+ } catch (error) {
469
+ if (this._schemaCache.get(cacheKey) === promise) {
470
+ this._schemaCache.delete(cacheKey)
471
+ }
472
+
473
+ throw error
474
+ }
475
+ }
476
+
477
+ /**
478
+ * Runs cached table schema metadata.
479
+ * @template T
480
+ * @param {string} tableName - Table name.
481
+ * @param {string} metadataName - Metadata name.
482
+ * @param {() => Promise<T>} callback - Cache miss callback.
483
+ * @returns {Promise<T>} - Resolves with the cached table metadata.
484
+ */
485
+ async _cachedTableSchemaMetadata(tableName, metadataName, callback) {
486
+ return await this._cachedSchemaMetadata(`table:${tableName}:${metadataName}`, callback)
487
+ }
488
+
489
+ /**
490
+ * Runs schema cache return value.
491
+ * @param {?} value - Cached value.
492
+ * @returns {?} - Value returned to callers.
493
+ */
494
+ _schemaCacheReturnValue(value) {
495
+ if (Array.isArray(value)) return value.slice()
496
+
497
+ return value
498
+ }
499
+
500
+ /**
501
+ * Runs get tables.
502
+ * @abstract
503
+ * @returns {Promise<Array<import("./base-table.js").default>>} - Resolves with the tables.
504
+ */
505
+ getTables() {
506
+ throw new Error(`${this.constructor.name}#getTables not implemented`)
507
+ }
508
+
509
+ /**
510
+ * Runs structure sql.
511
+ * @returns {Promise<string | null>} - Resolves with SQL string.
512
+ */
513
+ async structureSql() {
514
+ return null
515
+ }
516
+
517
+ /**
518
+ * Runs get table by name.
519
+ * @param {string} name - Name.
520
+ * @param {object} [args] - Options object.
521
+ * @param {boolean} args.throwError - Whether throw error.
522
+ * @returns {Promise<import("./base-table.js").default | undefined>} - Resolves with the table by name.
523
+ */
524
+ async getTableByName(name, args) {
525
+ const tables = await this.getTables()
526
+ const tableNames = []
527
+ let table
528
+
529
+ for (const candidate of tables) {
530
+ const candidateName = candidate.getName()
531
+
532
+ if (candidateName == name) {
533
+ table = candidate
534
+ break
535
+ }
536
+
537
+ tableNames.push(candidateName)
538
+ }
539
+
540
+ if (!table && args?.throwError !== false) {
541
+ throw new Error(this._missingTableErrorMessage(name, tableNames))
542
+ }
543
+
544
+ return table
545
+ }
546
+
547
+ /**
548
+ * Runs missing table error message.
549
+ * @param {string} name - Table name.
550
+ * @param {string[]} tableNames - Available table names.
551
+ * @returns {string} - Error message.
552
+ */
553
+ _missingTableErrorMessage(name, tableNames) {
554
+ const environment = this.getConfiguration().getEnvironment()
555
+ const args = this.getArgs()
556
+ const databaseName = args?.database || args?.name || args?.useDatabase || "unknown"
557
+
558
+ return `Couldn't find a table by that name "${name}" in: ${tableNames.join(", ")} (environment: ${environment}, database: ${databaseName})`
559
+ }
560
+
561
+ /**
562
+ * Runs get table by name or fail.
563
+ * @param {string} name - Name.
564
+ * @returns {Promise<import("./base-table.js").default>} - Resolves with the table by name or fail.
565
+ */
566
+ async getTableByNameOrFail(name) {
567
+ return /** Narrows the runtime value to the documented type. @type {import("./base-table.js").default} */ (await this.getTableByName(name, {throwError: true}))
568
+ }
569
+
570
+ /**
571
+ * Runs get type.
572
+ * @abstract
573
+ * @returns {string} - The type.
574
+ */
575
+ getType() {
576
+ throw new Error("'type' not implemented")
577
+ }
578
+
579
+ /**
580
+ * Runs insert.
581
+ * @param {InsertSqlArgsType} args - Options object.
582
+ * @returns {Promise<void>} - Resolves when complete.
583
+ */
584
+ async insert(args) {
585
+ this._assertNotReadOnly()
586
+ const sql = this.insertSql(args)
587
+
588
+ await this.query(sql)
589
+ }
590
+
591
+ /**
592
+ * Runs insert multiple.
593
+ * @param {string} tableName - Table name.
594
+ * @param {Array<string>} columns - Column names.
595
+ * @param {Array<Array<?>>} rows - Rows to insert.
596
+ * @returns {Promise<void>} - Resolves when complete.
597
+ */
598
+ async insertMultiple(tableName, columns, rows) {
599
+ this._assertNotReadOnly()
600
+
601
+ const sql = this.insertSql({columns, tableName, rows})
602
+
603
+ await this.query(sql)
604
+ }
605
+
606
+ /**
607
+ * Runs insert sql.
608
+ * @abstract
609
+ * @param {InsertSqlArgsType} args - Options object.
610
+ * @returns {string} - SQL string.
611
+ */
612
+ insertSql(args) { // eslint-disable-line no-unused-vars
613
+ throw new Error("'insertSql' not implemented")
614
+ }
615
+
616
+ /**
617
+ * Runs upsert.
618
+ * @param {UpsertSqlArgsType} args - Options object.
619
+ * @returns {Promise<void>} - Resolves when complete.
620
+ */
621
+ async upsert(args) {
622
+ this._assertNotReadOnly()
623
+ const sql = this.upsertSql(args)
624
+
625
+ await this.query(sql)
626
+ }
627
+
628
+ /**
629
+ * Runs last insert id.
630
+ * @abstract
631
+ * @returns {Promise<number>} - Resolves with the last insert id.
632
+ */
633
+ lastInsertID() {
634
+ throw new Error(`${this.constructor.name}#lastInsertID not implemented`)
635
+ }
636
+
637
+ /**
638
+ * Runs convert value.
639
+ * @param {?} value - Value to use.
640
+ * @returns {?} - The convert value.
641
+ */
642
+ _convertValue(value) {
643
+ if (typeof value === "boolean") {
644
+ return value ? 1 : 0
645
+ }
646
+
647
+ if (value instanceof Date) {
648
+ return strftime("%F %T.%L", value)
649
+ }
650
+
651
+ // JSON-encode plain objects/arrays so they land in JSON/text columns as valid
652
+ // JSON. Without this, drivers like mysql's escape() turn an object into
653
+ // `key` = value assignment pairs (its `SET ?` form), producing invalid SQL in
654
+ // a value position. Only PLAIN objects and arrays are encoded — class
655
+ // instances (e.g. model records, which are circular via _changes) and Buffers
656
+ // pass through untouched, since JSON.stringify on a record throws on its
657
+ // circular structure and a record is never a valid column value to serialize.
658
+ if (this._isJsonEncodableValue(value)) {
659
+ return JSON.stringify(value)
660
+ }
661
+
662
+ return value
663
+ }
664
+
665
+ /**
666
+ * Whether a value is a plain object or array that should be JSON-encoded for a
667
+ * JSON/text column. Excludes Buffers and class instances (e.g. model records).
668
+ * @param {?} value - Value to test.
669
+ * @returns {boolean} - Whether to JSON-encode the value.
670
+ */
671
+ _isJsonEncodableValue(value) {
672
+ if (value === null || typeof value !== "object") return false
673
+ if (typeof Buffer !== "undefined" && Buffer.isBuffer(value)) return false
674
+ if (Array.isArray(value)) return true
675
+
676
+ const prototype = Object.getPrototypeOf(value)
677
+
678
+ return prototype === Object.prototype || prototype === null
679
+ }
680
+
681
+ /**
682
+ * Runs options.
683
+ * @abstract
684
+ * @returns {import("../query-parser/options.js").default} - The options options.
685
+ */
686
+ options() {
687
+ throw new Error("'options' not implemented.")
688
+ }
689
+
690
+ /**
691
+ * Runs quote.
692
+ * @param {?} value - Value to use.
693
+ * @returns {number | string} - The quote.
694
+ */
695
+ quote(value) {
696
+ if (typeof value == "number") return value
697
+
698
+ const escapedValue = this.escape(value)
699
+ const result = `"${escapedValue}"`
700
+
701
+ return result
702
+ }
703
+
704
+ /**
705
+ * Runs quote column.
706
+ * @param {string} columnName - Column name.
707
+ * @returns {string} - The quote column.
708
+ */
709
+ quoteColumn(columnName) {
710
+ return this.options().quoteColumnName(columnName)
711
+ }
712
+
713
+ /**
714
+ * Runs quote index.
715
+ * @param {string} columnName - Column name.
716
+ * @returns {string} - The quote index.
717
+ */
718
+ quoteIndex(columnName) {
719
+ return this.options().quoteIndexName(columnName)
720
+ }
721
+
722
+ /**
723
+ * Runs quote table.
724
+ * @param {string} tableName - Table name.
725
+ * @returns {string} - The quote table.
726
+ */
727
+ quoteTable(tableName) {
728
+ return this.options().quoteTableName(tableName)
729
+ }
730
+
731
+ /**
732
+ * Runs new query.
733
+ * @returns {Query} - The new query.
734
+ */
735
+ newQuery() {
736
+ const handler = new Handler()
737
+
738
+ return new Query({
739
+ driver: this,
740
+ handler
741
+ })
742
+ }
743
+
744
+ /**
745
+ * Runs select.
746
+ * @param {string} tableName - Table name.
747
+ * @returns {Promise<QueryResultType>} - Resolves with the select.
748
+ */
749
+ async select(tableName) {
750
+ const query = this.newQuery()
751
+
752
+ const sql = query
753
+ .from(tableName)
754
+ .toSql()
755
+
756
+ return await this.query(sql)
757
+ }
758
+
759
+ /**
760
+ * Runs set id seq.
761
+ * @param {number | undefined} newIdSeq - New id seq.
762
+ * @returns {void} - No return value.
763
+ */
764
+ setIdSeq(newIdSeq) {
765
+ this.idSeq = newIdSeq
766
+ }
767
+
768
+ /**
769
+ * Runs should set auto increment when primary key.
770
+ * @abstract
771
+ * @returns {boolean} - Whether set auto increment when primary key.
772
+ */
773
+ shouldSetAutoIncrementWhenPrimaryKey() {
774
+ throw new Error(`'shouldSetAutoIncrementWhenPrimaryKey' not implemented`)
775
+ }
776
+
777
+ /**
778
+ * Runs supports default primary key uuid.
779
+ * @returns {boolean} - Whether supports default primary key uuid.
780
+ */
781
+ supportsDefaultPrimaryKeyUUID() { return false }
782
+
783
+ /**
784
+ * Runs supports insert into returning.
785
+ * @abstract
786
+ * @returns {boolean} - Whether supports insert into returning.
787
+ */
788
+ supportsInsertIntoReturning() { return false }
789
+
790
+ /**
791
+ * Runs table exists.
792
+ * @param {string} tableName - Table name.
793
+ * @returns {Promise<boolean>} - Resolves with Whether table exists.
794
+ */
795
+ async tableExists(tableName) {
796
+ const tables = await this.getTables()
797
+ const table = tables.find((table) => table.getName() == tableName)
798
+
799
+ if (table) return true
800
+
801
+ return false
802
+ }
803
+
804
+ /**
805
+ * Runs transaction.
806
+ * @param {() => Promise<void>} callback - Callback function.
807
+ * @returns {Promise<?>} - Resolves with the transaction.
808
+ */
809
+ async transaction(callback) {
810
+ const savePointName = this.generateSavePointName()
811
+ /**
812
+ * Callback frame.
813
+ @type {Array<() => void | Promise<void>>} */
814
+ const callbackFrame = []
815
+ let transactionStarted = false
816
+ let savePointStarted = false
817
+
818
+ this._afterCommitCallbackFrames.push(callbackFrame)
819
+
820
+ if (this._transactionsCount == 0) {
821
+ this.logger.debug("Start transaction")
822
+ await this.startTransaction()
823
+ transactionStarted = true
824
+ } else {
825
+ this.logger.debug("Start savepoint", savePointName)
826
+ await this.startSavePoint(savePointName)
827
+ savePointStarted = true
828
+ }
829
+
830
+ let result
831
+
832
+ try {
833
+ result = await callback()
834
+
835
+ if (savePointStarted) {
836
+ this.logger.debug("Release savepoint", savePointName)
837
+ await this.releaseSavePoint(savePointName)
838
+ }
839
+
840
+ if (transactionStarted) {
841
+ this.logger.debug("Commit transaction")
842
+ await this.commitTransaction()
843
+ }
844
+
845
+ await this._commitAfterCommitCallbackFrame()
846
+ } catch (error) {
847
+ if (error instanceof Error) {
848
+ this.logger.debug("Transaction error", error.message)
849
+ } else {
850
+ this.logger.debug("Transaction error", error)
851
+ }
852
+
853
+ let transactionRolledBack = false
854
+
855
+ if (savePointStarted) {
856
+ this.logger.debug("Rollback savepoint", savePointName)
734
857
  try {
735
- result = await callback();
736
- if (savePointStarted) {
737
- this.logger.debug("Release savepoint", savePointName);
738
- await this.releaseSavePoint(savePointName);
739
- }
740
- if (transactionStarted) {
741
- this.logger.debug("Commit transaction");
742
- await this.commitTransaction();
743
- }
744
- await this._commitAfterCommitCallbackFrame();
858
+ await this.rollbackSavePoint(savePointName)
859
+ } catch (savePointError) {
860
+ const message = savePointError instanceof Error ? savePointError.message : `${savePointError}`
861
+
862
+ // MySQL sometimes drops savepoints unexpectedly; fall back to rolling back the full transaction
863
+ if (message.includes("SAVEPOINT") || message.includes("ER_SP_DOES_NOT_EXIST")) {
864
+ this.logger.debug("Savepoint rollback failed; rolling back entire transaction instead")
865
+ await this.rollbackTransaction()
866
+ transactionRolledBack = true
867
+ } else {
868
+ throw savePointError
869
+ }
745
870
  }
746
- catch (error) {
747
- if (error instanceof Error) {
748
- this.logger.debug("Transaction error", error.message);
871
+ }
872
+
873
+ if (transactionStarted && !transactionRolledBack) {
874
+ this.logger.debug("Rollback transaction")
875
+ await this.rollbackTransaction()
876
+ }
877
+
878
+ this._afterCommitCallbackFrames.pop()
879
+
880
+ throw error
881
+ }
882
+
883
+ return result
884
+ }
885
+
886
+ /**
887
+ * Runs a callback after the surrounding transaction commits.
888
+ * If no transaction is active, the callback runs immediately.
889
+ * @param {() => void | Promise<void>} callback - Callback.
890
+ * @returns {Promise<void>} - Resolves when the callback has been registered or run.
891
+ */
892
+ async afterCommit(callback) {
893
+ const currentFrame = this._afterCommitCallbackFrames[this._afterCommitCallbackFrames.length - 1]
894
+
895
+ if (!currentFrame) {
896
+ await callback()
897
+ return
898
+ }
899
+
900
+ currentFrame.push(callback)
901
+ }
902
+
903
+ /**
904
+ * Runs start transaction.
905
+ * @returns {Promise<void>} - Resolves when complete.
906
+ */
907
+ async startTransaction() {
908
+ await this._transactionsActionsMutex.sync(async () => {
909
+ await this._startTransactionAction()
910
+ this._transactionsCount++
911
+ })
912
+ }
913
+
914
+ /**
915
+ * Runs start transaction action.
916
+ * @returns {Promise<void>} - Resolves when complete.
917
+ */
918
+ async _startTransactionAction() {
919
+ await this.query("BEGIN TRANSACTION")
920
+ }
921
+
922
+ /**
923
+ * Runs commit transaction.
924
+ * @returns {Promise<void>} - Resolves when complete.
925
+ */
926
+ async commitTransaction() {
927
+ await this._transactionsActionsMutex.sync(async () => {
928
+ await this._commitTransactionAction()
929
+ this._transactionsCount--
930
+ })
931
+ }
932
+
933
+ /**
934
+ * Runs commit transaction action.
935
+ * @returns {Promise<void>} - Resolves when complete.
936
+ */
937
+ async _commitTransactionAction() {
938
+ await this.query("COMMIT")
939
+ }
940
+
941
+ /**
942
+ * Merges committed callbacks into the parent transaction frame or runs them when the outermost commit completes.
943
+ * @returns {Promise<void>} - Resolves when complete.
944
+ */
945
+ async _commitAfterCommitCallbackFrame() {
946
+ const committedCallbacks = this._afterCommitCallbackFrames.pop()
947
+
948
+ if (!committedCallbacks || committedCallbacks.length === 0) return
949
+
950
+ const parentFrame = this._afterCommitCallbackFrames[this._afterCommitCallbackFrames.length - 1]
951
+
952
+ if (parentFrame) {
953
+ parentFrame.push(...committedCallbacks)
954
+ return
955
+ }
956
+
957
+ for (const callback of committedCallbacks) {
958
+ await callback()
959
+ }
960
+ }
961
+
962
+ /**
963
+ * Runs query.
964
+ * @param {string} sql - SQL string.
965
+ * @param {QueryOptions} [options] - Query options.
966
+ * @returns {Promise<QueryResultType>} - Resolves with the query.
967
+ */
968
+ async query(sql, options = {}) {
969
+ this._assertWritableQuery(sql)
970
+
971
+ let tries = 0
972
+ const maxTries = 5
973
+ const requestTiming = this.configuration.getCurrentRequestTiming()
974
+ const logQuery = options.logQuery ?? this._queryLoggingEnabled()
975
+ const sourceStack = logQuery ? (options.sourceStack || Error().stack) : undefined
976
+ const querySql = this._querySqlWithProcessListComment(sql, options)
977
+
978
+ while (tries < maxTries) {
979
+ tries++
980
+
981
+ try {
982
+ return await this._queryActualWithLogging({originalSql: sql, querySql}, {...options, logQuery, sourceStack}, requestTiming, tries)
983
+ } catch (error) {
984
+ if (!(error instanceof Error)) throw error
985
+
986
+ const retryInfo = this.retryableDatabaseError(error)
987
+
988
+ if (tries < maxTries && retryInfo.retry) {
989
+ if (retryInfo.reconnect) {
990
+ if (this._transactionsCount > 0) {
991
+ throw new Error(`Cannot reconnect while a transaction is active (${this._transactionsCount}). Original error: ${error.message}`, {cause: error})
749
992
  }
750
- else {
751
- this.logger.debug("Transaction error", error);
752
- }
753
- let transactionRolledBack = false;
754
- if (savePointStarted) {
755
- this.logger.debug("Rollback savepoint", savePointName);
756
- try {
757
- await this.rollbackSavePoint(savePointName);
758
- }
759
- catch (savePointError) {
760
- const message = savePointError instanceof Error ? savePointError.message : `${savePointError}`;
761
- // MySQL sometimes drops savepoints unexpectedly; fall back to rolling back the full transaction
762
- if (message.includes("SAVEPOINT") || message.includes("ER_SP_DOES_NOT_EXIST")) {
763
- this.logger.debug("Savepoint rollback failed; rolling back entire transaction instead");
764
- await this.rollbackTransaction();
765
- transactionRolledBack = true;
766
- }
767
- else {
768
- throw savePointError;
769
- }
770
- }
771
- }
772
- if (transactionStarted && !transactionRolledBack) {
773
- this.logger.debug("Rollback transaction");
774
- await this.rollbackTransaction();
775
- }
776
- this._afterCommitCallbackFrames.pop();
777
- throw error;
778
- }
779
- return result;
780
- }
781
- /**
782
- * Runs a callback after the surrounding transaction commits.
783
- * If no transaction is active, the callback runs immediately.
784
- * @param {() => void | Promise<void>} callback - Callback.
785
- * @returns {Promise<void>} - Resolves when the callback has been registered or run.
786
- */
787
- async afterCommit(callback) {
788
- const currentFrame = this._afterCommitCallbackFrames[this._afterCommitCallbackFrames.length - 1];
789
- if (!currentFrame) {
790
- await callback();
791
- return;
792
- }
793
- currentFrame.push(callback);
794
- }
795
- /**
796
- * Runs start transaction.
797
- * @returns {Promise<void>} - Resolves when complete.
798
- */
799
- async startTransaction() {
800
- await this._transactionsActionsMutex.sync(async () => {
801
- await this._startTransactionAction();
802
- this._transactionsCount++;
803
- });
804
- }
805
- /**
806
- * Runs start transaction action.
807
- * @returns {Promise<void>} - Resolves when complete.
808
- */
809
- async _startTransactionAction() {
810
- await this.query("BEGIN TRANSACTION");
811
- }
812
- /**
813
- * Runs commit transaction.
814
- * @returns {Promise<void>} - Resolves when complete.
815
- */
816
- async commitTransaction() {
817
- await this._transactionsActionsMutex.sync(async () => {
818
- await this._commitTransactionAction();
819
- this._transactionsCount--;
820
- });
821
- }
822
- /**
823
- * Runs commit transaction action.
824
- * @returns {Promise<void>} - Resolves when complete.
825
- */
826
- async _commitTransactionAction() {
827
- await this.query("COMMIT");
828
- }
829
- /**
830
- * Merges committed callbacks into the parent transaction frame or runs them when the outermost commit completes.
831
- * @returns {Promise<void>} - Resolves when complete.
832
- */
833
- async _commitAfterCommitCallbackFrame() {
834
- const committedCallbacks = this._afterCommitCallbackFrames.pop();
835
- if (!committedCallbacks || committedCallbacks.length === 0)
836
- return;
837
- const parentFrame = this._afterCommitCallbackFrames[this._afterCommitCallbackFrames.length - 1];
838
- if (parentFrame) {
839
- parentFrame.push(...committedCallbacks);
840
- return;
841
- }
842
- for (const callback of committedCallbacks) {
843
- await callback();
993
+
994
+ await this.reconnect()
995
+ }
996
+
997
+ const waitMs = typeof retryInfo.waitMs === "number" && Number.isFinite(retryInfo.waitMs) ? retryInfo.waitMs : 100
998
+
999
+ if (waitMs > 0) await wait(waitMs)
1000
+ this.logger.warn(`Retrying query because failed with: ${error.stack}`)
1001
+ // Retry
1002
+ } else {
1003
+ throw error
844
1004
  }
845
- }
846
- /**
847
- * Runs query.
848
- * @param {string} sql - SQL string.
849
- * @param {QueryOptions} [options] - Query options.
850
- * @returns {Promise<QueryResultType>} - Resolves with the query.
851
- */
852
- async query(sql, options = {}) {
853
- this._assertWritableQuery(sql);
854
- let tries = 0;
855
- const maxTries = 5;
856
- const requestTiming = this.configuration.getCurrentRequestTiming();
857
- const logQuery = options.logQuery ?? this._queryLoggingEnabled();
858
- const sourceStack = logQuery ? (options.sourceStack || Error().stack) : undefined;
859
- const querySql = this._querySqlWithProcessListComment(sql, options);
860
- while (tries < maxTries) {
861
- tries++;
1005
+ }
1006
+ }
1007
+
1008
+ throw new Error("'query' unexpected came here")
1009
+ }
1010
+
1011
+ /**
1012
+ * Runs query actual with logging.
1013
+ * @param {object} args - Options object.
1014
+ * @param {string} args.originalSql - Original SQL string before process-list comments.
1015
+ * @param {string} args.querySql - SQL string sent to the database.
1016
+ * @param {QueryOptions} options - Query options.
1017
+ * @param {import("../../http-server/client/request-timing.js").default | undefined} requestTiming - Request timing.
1018
+ * @param {number} tries - Query attempt count.
1019
+ * @returns {Promise<QueryResultType>} - Resolves with the query.
1020
+ */
1021
+ async _queryActualWithLogging({originalSql, querySql}, options, requestTiming, tries) {
1022
+ const startedAtMs = nowMs()
1023
+ const previousActiveQuery = this._activeQuery
1024
+ this._activeQuery = {
1025
+ annotations: getDatabaseAnnotations(),
1026
+ logName: options.logName || "SQL",
1027
+ sqlPreview: this._debugSqlPreview(originalSql),
1028
+ startedAtUnixMs: Date.now()
1029
+ }
1030
+ let result
1031
+
1032
+ try {
1033
+ if (requestTiming && tries === 1) {
1034
+ result = await requestTiming.measureDbQuery(async () => await this._queryActual(querySql))
1035
+ } else if (requestTiming) {
1036
+ result = await requestTiming.measure("db", async () => await this._queryActual(querySql))
1037
+ } else {
1038
+ result = await this._queryActual(querySql)
1039
+ }
1040
+ } finally {
1041
+ this._activeQuery = previousActiveQuery
1042
+ }
1043
+
1044
+ const elapsedMs = nowMs() - startedAtMs
1045
+
1046
+ if (options.logQuery !== false) {
1047
+ await this._logQuery({
1048
+ elapsedMs,
1049
+ logName: options.logName || "SQL",
1050
+ sourceStack: options.sourceStack,
1051
+ sql: originalSql
1052
+ })
1053
+ }
1054
+
1055
+ if (this._schemaCacheInvalidatingSql(originalSql)) {
1056
+ this.clearSchemaCache()
1057
+ }
1058
+
1059
+ return result
1060
+ }
1061
+
1062
+ /**
1063
+ * Runs get debug snapshot.
1064
+ * @returns {DatabaseConnectionDebugSnapshot} - Diagnostic snapshot for this connection.
1065
+ */
1066
+ getDebugSnapshot() {
1067
+ const now = Date.now()
1068
+ const activeQuery = this._activeQuery
1069
+
1070
+ return {
1071
+ activeQuery: activeQuery ? {...activeQuery, runningMs: Math.max(0, now - activeQuery.startedAtUnixMs)} : null,
1072
+ checkoutAgeMs: this._connectionCheckedOutAtUnixMs ? Math.max(0, now - this._connectionCheckedOutAtUnixMs) : undefined,
1073
+ checkedOutAtUnixMs: this._connectionCheckedOutAtUnixMs,
1074
+ checkoutName: this._connectionCheckoutName,
1075
+ driverClass: this.constructor.name,
1076
+ idSeq: this.idSeq,
1077
+ openTransactions: this._transactionsCount,
1078
+ schemaCacheEntries: this._schemaCache.size
1079
+ }
1080
+ }
1081
+
1082
+ /**
1083
+ * Runs debug sql preview.
1084
+ * @param {string} sql - SQL to preview.
1085
+ * @returns {string} - Normalized truncated SQL preview for diagnostics.
1086
+ */
1087
+ _debugSqlPreview(sql) {
1088
+ return sql
1089
+ .replace(/\s+/g, " ")
1090
+ .trim()
1091
+ .slice(0, 500)
1092
+ }
1093
+
1094
+ /**
1095
+ * Runs query sql with process list comment.
1096
+ * @param {string} sql - SQL string.
1097
+ * @param {QueryOptions} options - Query options.
1098
+ * @returns {string} - SQL string with a leading process-list comment when annotations exist.
1099
+ */
1100
+ _querySqlWithProcessListComment(sql, options) {
1101
+ if (options.processListComment === false) return sql
1102
+
1103
+ const parts = []
1104
+
1105
+ if (this._connectionCheckoutName) {
1106
+ parts.push(`checkout="${this._processListCommentValue(this._connectionCheckoutName)}"`)
1107
+ }
1108
+
1109
+ const annotations = getDatabaseAnnotations()
1110
+
1111
+ if (annotations.length > 0) {
1112
+ parts.push(`annotations="${this._processListCommentValue(annotations.join(" > "))}"`)
1113
+ }
1114
+
1115
+ if (parts.length === 0) return sql
1116
+
1117
+ return `/* velocious ${parts.join(" ")} */ ${sql}`
1118
+ }
1119
+
1120
+ /**
1121
+ * Runs process list comment value.
1122
+ * @param {string} value - Raw process-list comment value.
1123
+ * @returns {string} - Sanitized process-list comment value.
1124
+ */
1125
+ _processListCommentValue(value) {
1126
+ let sanitized = ""
1127
+
1128
+ for (const character of value) {
1129
+ const codePoint = character.codePointAt(0)
1130
+
1131
+ sanitized += codePoint !== undefined && (codePoint < 32 || codePoint === 127) ? " " : character
1132
+ }
1133
+
1134
+ return sanitized
1135
+ .replace(/\*\//g, "* /")
1136
+ .replace(/\s+/g, " ")
1137
+ .trim()
1138
+ .slice(0, 200)
1139
+ .replace(/"/g, "'")
1140
+ }
1141
+
1142
+ /**
1143
+ * Runs schema cache invalidating sql.
1144
+ * @param {string} sql - SQL string.
1145
+ * @returns {boolean} - Whether the SQL should invalidate schema metadata.
1146
+ */
1147
+ _schemaCacheInvalidatingSql(sql) {
1148
+ const normalized = sql
1149
+ .trim()
1150
+ .replace(/^\ufeff/, "")
1151
+ .replace(/\/\*[\s\S]*?\*\//g, " ")
1152
+ .replace(/--[^\n]*(\n|$)/g, " ")
1153
+ .replace(/\s+/g, " ")
1154
+ .toLowerCase()
1155
+
1156
+ if (!normalized) return false
1157
+ if (/^(create|alter|drop|rename)\b/.test(normalized)) return true
1158
+ if (/^comment\s+on\b/.test(normalized)) return true
1159
+ if (/^exec(?:ute)?\s+sp_rename\b/.test(normalized)) return true
1160
+ if (/^if\b[\s\S]*\bbegin\s+(create|alter|drop|rename)\b/.test(normalized)) return true
1161
+
1162
+ return false
1163
+ }
1164
+
1165
+ /**
1166
+ * Runs query logging enabled.
1167
+ * @returns {boolean} - Whether query logging is enabled for this driver.
1168
+ */
1169
+ _queryLoggingEnabled() {
1170
+ if (typeof this.configuration?.getQueryLoggingEnabled !== "function") return true
1171
+ if (!this.configuration.getQueryLoggingEnabled()) return false
1172
+
1173
+ const logger = new Logger("SQL", {configuration: this.configuration})
1174
+
1175
+ return logger.isLevelEnabled("info")
1176
+ }
1177
+
1178
+ /**
1179
+ * Runs log query.
1180
+ * @param {object} args - Options object.
1181
+ * @param {number} args.elapsedMs - Elapsed milliseconds.
1182
+ * @param {string} args.logName - Query log subject.
1183
+ * @param {string | undefined} args.sourceStack - Source stack.
1184
+ * @param {string} args.sql - SQL string.
1185
+ * @returns {Promise<void>} - Resolves when complete.
1186
+ */
1187
+ async _logQuery({elapsedMs, logName, sourceStack, sql}) {
1188
+ const logger = new Logger(logName, {configuration: this.configuration})
1189
+ const sourceLine = this._querySourceLine(sourceStack)
1190
+ const message = sourceLine
1191
+ ? `(${formatElapsedMs(elapsedMs)}) ${sql}\n ↳ ${sourceLine}`
1192
+ : `(${formatElapsedMs(elapsedMs)}) ${sql}`
1193
+
1194
+ await logger.info(message)
1195
+ }
1196
+
1197
+ /**
1198
+ * Runs query source line.
1199
+ * @param {string | undefined} sourceStack - Source stack.
1200
+ * @returns {string | undefined} - Source line when an application frame is available.
1201
+ */
1202
+ _querySourceLine(sourceStack) {
1203
+ if (!sourceStack) return undefined
1204
+
1205
+ const applicationDirectory = typeof this.configuration?.getDirectoryIfAvailable === "function"
1206
+ ? this.configuration.getDirectoryIfAvailable()
1207
+ : this.configuration?.getDirectory?.()
1208
+
1209
+ if (!applicationDirectory) return undefined
1210
+
1211
+ const error = new Error("Query source")
1212
+
1213
+ error.stack = sourceStack
1214
+
1215
+ return BacktraceCleaner.getApplicationSourceLine(error, {
1216
+ applicationDirectory,
1217
+ frameworkSourceDirectory: this.configuration.getEnvironmentHandler().getFrameworkSourceDirectory()
1218
+ })
1219
+ }
1220
+
1221
+ /**
1222
+ * Runs query actual.
1223
+ * @abstract
1224
+ * @param {string} sql - SQL string.
1225
+ * @returns {Promise<QueryResultType>} - Resolves with the query actual.
1226
+ */
1227
+ _queryActual(sql) { // eslint-disable-line no-unused-vars
1228
+ throw new Error(`queryActual not implemented`)
1229
+ }
1230
+
1231
+ /**
1232
+ * Runs query to sql.
1233
+ * @abstract
1234
+ * @param {Query} _query - Query instance.
1235
+ * @returns {string} - SQL string.
1236
+ */
1237
+ queryToSql(_query) { throw new Error("queryToSql not implemented") }
1238
+
1239
+ /**
1240
+ * Runs retryable database error.
1241
+ * @param {Error} _error - Error instance.
1242
+ * @returns {RetryableDatabaseErrorResult} - Retry info.
1243
+ */
1244
+ retryableDatabaseError(_error) {
1245
+ return {retry: false, reconnect: false}
1246
+ }
1247
+
1248
+ /**
1249
+ * Runs assert writable query.
1250
+ * @param {string} sql - SQL string.
1251
+ * @returns {void} - No return value.
1252
+ */
1253
+ _assertWritableQuery(sql) {
1254
+ if (!this.isReadOnly()) return
1255
+ if (!this._sqlLooksLikeWrite(sql)) return
1256
+
1257
+ throw new Error("Database is read-only")
1258
+ }
1259
+
1260
+ /**
1261
+ * Runs assert not read only.
1262
+ * @returns {void} - No return value.
1263
+ */
1264
+ _assertNotReadOnly() {
1265
+ if (this.isReadOnly()) {
1266
+ throw new Error("Database is read-only")
1267
+ }
1268
+ }
1269
+
1270
+ /**
1271
+ * Runs sql looks like write.
1272
+ * @param {string} sql - SQL string.
1273
+ * @returns {boolean} - SQL representation.
1274
+ */
1275
+ _sqlLooksLikeWrite(sql) {
1276
+ const normalized = sql.trim().toLowerCase()
1277
+
1278
+ if (!normalized) return false
1279
+
1280
+ if (
1281
+ normalized.startsWith("select") ||
1282
+ normalized.startsWith("show") ||
1283
+ normalized.startsWith("pragma") ||
1284
+ normalized.startsWith("explain") ||
1285
+ normalized.startsWith("describe")
1286
+ ) {
1287
+ return false
1288
+ }
1289
+
1290
+ if (normalized.startsWith("with")) {
1291
+ const withMatch = normalized.match(/^\s*with[\s\S]+?\)\s*(select|insert|update|delete|merge|replace)\b/)
1292
+
1293
+ if (withMatch) {
1294
+ return withMatch[1] !== "select"
1295
+ }
1296
+
1297
+ return false
1298
+ }
1299
+
1300
+ const keywordMatch = normalized.match(/^\s*(\w+)/)
1301
+ const keyword = keywordMatch ? keywordMatch[1] : ""
1302
+
1303
+ return [
1304
+ "insert",
1305
+ "update",
1306
+ "delete",
1307
+ "create",
1308
+ "alter",
1309
+ "drop",
1310
+ "truncate",
1311
+ "merge",
1312
+ "replace"
1313
+ ].includes(keyword)
1314
+ }
1315
+
1316
+ /**
1317
+ * Runs is read only.
1318
+ * @returns {boolean} - Whether read only.
1319
+ */
1320
+ isReadOnly() {
1321
+ return Boolean(this.getArgs().readOnly)
1322
+ }
1323
+
1324
+ /**
1325
+ * Runs rollback transaction.
1326
+ * @returns {Promise<void>} - Resolves when complete.
1327
+ */
1328
+ async rollbackTransaction() {
1329
+ await this._transactionsActionsMutex.sync(async () => {
1330
+ try {
1331
+ await this._rollbackTransactionAction()
1332
+ } finally {
1333
+ this._transactionsCount--
1334
+
1335
+ // A rolled-back transaction may have reverted DDL (e.g. a CREATE TABLE
1336
+ // run lazily inside the transaction), so any cached schema metadata is
1337
+ // now stale and must be invalidated. Without this, a later tableExists()
1338
+ // check can report a table that the rollback already removed, so callers
1339
+ // skip recreating it and then fail with "no such table".
1340
+ this.clearSchemaCache()
1341
+ }
1342
+ })
1343
+ }
1344
+
1345
+ /**
1346
+ * Runs rollback transaction action.
1347
+ * @returns {Promise<void>} - Resolves when complete.
1348
+ */
1349
+ async _rollbackTransactionAction() {
1350
+ await this.query("ROLLBACK")
1351
+ }
1352
+
1353
+ /**
1354
+ * Runs generate save point name.
1355
+ * @returns {string} - The generate save point name.
1356
+ */
1357
+ generateSavePointName() {
1358
+ return `sp${new UUID(4).format().replaceAll("-", "")}`
1359
+ }
1360
+
1361
+ /**
1362
+ * Runs start save point.
1363
+ * @param {string} savePointName - Save point name.
1364
+ * @returns {Promise<void>} - Resolves when complete.
1365
+ */
1366
+ async startSavePoint(savePointName) {
1367
+ await this._transactionsActionsMutex.sync(async () => {
1368
+ await this._startSavePointAction(savePointName)
1369
+ })
1370
+ }
1371
+
1372
+ /**
1373
+ * Runs start save point action.
1374
+ * @param {string} savePointName - Save point name.
1375
+ * @returns {Promise<void>} - Resolves when complete.
1376
+ */
1377
+ async _startSavePointAction(savePointName) {
1378
+ await this.query(`SAVEPOINT ${savePointName}`)
1379
+ }
1380
+
1381
+ /**
1382
+ * Runs rename column.
1383
+ * @param {string} tableName - Table name.
1384
+ * @param {string} oldColumnName - Previous column name.
1385
+ * @param {string} newColumnName - New column name.
1386
+ * @returns {Promise<void>} - Resolves when complete.
1387
+ */
1388
+ async renameColumn(tableName, oldColumnName, newColumnName) {
1389
+ this._assertNotReadOnly()
1390
+ const tableColumn = new TableColumn(oldColumnName)
1391
+
1392
+ tableColumn.setNewName(newColumnName)
1393
+
1394
+ const tableData = new TableData(tableName)
1395
+
1396
+ tableData.addColumn(tableColumn)
1397
+
1398
+ const alterTableSQLs = await this.alterTableSQLs(tableData)
1399
+
1400
+ for (const alterTableSQL of alterTableSQLs) {
1401
+ await this.query(alterTableSQL)
1402
+ }
1403
+ }
1404
+
1405
+ /**
1406
+ * Runs release save point.
1407
+ * @param {string} savePointName - Save point name.
1408
+ * @returns {Promise<void>} - Resolves when complete.
1409
+ */
1410
+ async releaseSavePoint(savePointName) {
1411
+ await this._transactionsActionsMutex.sync(async () => {
1412
+ await this._releaseSavePointAction(savePointName)
1413
+ })
1414
+ }
1415
+
1416
+ /**
1417
+ * Runs release save point action.
1418
+ * @param {string} savePointName - Save point name.
1419
+ * @returns {Promise<void>} - Resolves when complete.
1420
+ */
1421
+ async _releaseSavePointAction(savePointName) {
1422
+ try {
1423
+ await this.query(`RELEASE SAVEPOINT ${savePointName}`)
1424
+ } catch (error) {
1425
+ const message = error instanceof Error ? error.message : `${error}`
1426
+
1427
+ // Savepoint may already be gone if the database rolled back automatically
1428
+ if (message.toLowerCase().includes("savepoint") && message.toLowerCase().includes("does not exist")) {
1429
+ this.logger.debug(`Release savepoint ignored because it no longer exists: ${savePointName}`)
1430
+ return
1431
+ }
1432
+
1433
+ throw error
1434
+ }
1435
+ }
1436
+
1437
+ /**
1438
+ * Runs rollback save point.
1439
+ * @param {string} savePointName - Save point name.
1440
+ * @returns {Promise<void>} - Resolves when complete.
1441
+ */
1442
+ async rollbackSavePoint(savePointName) {
1443
+ await this._transactionsActionsMutex.sync(async () => {
1444
+ await this._rollbackSavePointAction(savePointName)
1445
+ })
1446
+ }
1447
+
1448
+ /**
1449
+ * Runs rollback save point action.
1450
+ * @param {string} savePointName - Save point name.
1451
+ * @returns {Promise<void>} - Resolves when complete.
1452
+ */
1453
+ async _rollbackSavePointAction(savePointName) {
1454
+ await this.query(`ROLLBACK TO SAVEPOINT ${savePointName}`)
1455
+ }
1456
+
1457
+ /**
1458
+ * Runs truncate all tables.
1459
+ * @returns {Promise<void>} - Resolves when complete.
1460
+ */
1461
+ async truncateAllTables() {
1462
+ this._assertNotReadOnly()
1463
+ await this.withDisabledForeignKeys(async () => {
1464
+ let tries = 0
1465
+
1466
+ while(tries <= 5) {
1467
+ tries++
1468
+
1469
+ const tables = await this.getTables()
1470
+ const truncateErrors = []
1471
+
1472
+ for (const table of tables) {
1473
+ if (table.getName() != "schema_migrations") {
862
1474
  try {
863
- return await this._queryActualWithLogging({ originalSql: sql, querySql }, { ...options, logQuery, sourceStack }, requestTiming, tries);
864
- }
865
- catch (error) {
866
- if (!(error instanceof Error))
867
- throw error;
868
- const retryInfo = this.retryableDatabaseError(error);
869
- if (tries < maxTries && retryInfo.retry) {
870
- if (retryInfo.reconnect) {
871
- if (this._transactionsCount > 0) {
872
- throw new Error(`Cannot reconnect while a transaction is active (${this._transactionsCount}). Original error: ${error.message}`, { cause: error });
873
- }
874
- await this.reconnect();
875
- }
876
- const waitMs = typeof retryInfo.waitMs === "number" && Number.isFinite(retryInfo.waitMs) ? retryInfo.waitMs : 100;
877
- if (waitMs > 0)
878
- await wait(waitMs);
879
- this.logger.warn(`Retrying query because failed with: ${error.stack}`);
880
- // Retry
881
- }
882
- else {
883
- throw error;
884
- }
885
- }
886
- }
887
- throw new Error("'query' unexpected came here");
888
- }
889
- /**
890
- * Runs query actual with logging.
891
- * @param {object} args - Options object.
892
- * @param {string} args.originalSql - Original SQL string before process-list comments.
893
- * @param {string} args.querySql - SQL string sent to the database.
894
- * @param {QueryOptions} options - Query options.
895
- * @param {import("../../http-server/client/request-timing.js").default | undefined} requestTiming - Request timing.
896
- * @param {number} tries - Query attempt count.
897
- * @returns {Promise<QueryResultType>} - Resolves with the query.
898
- */
899
- async _queryActualWithLogging({ originalSql, querySql }, options, requestTiming, tries) {
900
- const startedAtMs = nowMs();
901
- const previousActiveQuery = this._activeQuery;
902
- this._activeQuery = {
903
- annotations: getDatabaseAnnotations(),
904
- logName: options.logName || "SQL",
905
- sqlPreview: this._debugSqlPreview(originalSql),
906
- startedAtUnixMs: Date.now()
907
- };
908
- let result;
909
- try {
910
- if (requestTiming && tries === 1) {
911
- result = await requestTiming.measureDbQuery(async () => await this._queryActual(querySql));
912
- }
913
- else if (requestTiming) {
914
- result = await requestTiming.measure("db", async () => await this._queryActual(querySql));
915
- }
916
- else {
917
- result = await this._queryActual(querySql);
1475
+ await table.truncate({cascade: true})
1476
+ } catch (error) {
1477
+ console.error(error)
1478
+ truncateErrors.push(error)
918
1479
  }
1480
+ }
919
1481
  }
920
- finally {
921
- this._activeQuery = previousActiveQuery;
922
- }
923
- const elapsedMs = nowMs() - startedAtMs;
924
- if (options.logQuery !== false) {
925
- await this._logQuery({
926
- elapsedMs,
927
- logName: options.logName || "SQL",
928
- sourceStack: options.sourceStack,
929
- sql: originalSql
930
- });
931
- }
932
- if (this._schemaCacheInvalidatingSql(originalSql)) {
933
- this.clearSchemaCache();
934
- }
935
- return result;
936
- }
937
- /**
938
- * Runs get debug snapshot.
939
- * @returns {DatabaseConnectionDebugSnapshot} - Diagnostic snapshot for this connection.
940
- */
941
- getDebugSnapshot() {
942
- const now = Date.now();
943
- const activeQuery = this._activeQuery;
944
- return {
945
- activeQuery: activeQuery ? { ...activeQuery, runningMs: Math.max(0, now - activeQuery.startedAtUnixMs) } : null,
946
- checkoutAgeMs: this._connectionCheckedOutAtUnixMs ? Math.max(0, now - this._connectionCheckedOutAtUnixMs) : undefined,
947
- checkedOutAtUnixMs: this._connectionCheckedOutAtUnixMs,
948
- checkoutName: this._connectionCheckoutName,
949
- driverClass: this.constructor.name,
950
- idSeq: this.idSeq,
951
- openTransactions: this._transactionsCount,
952
- schemaCacheEntries: this._schemaCache.size
953
- };
954
- }
955
- /**
956
- * Runs debug sql preview.
957
- * @param {string} sql - SQL to preview.
958
- * @returns {string} - Normalized truncated SQL preview for diagnostics.
959
- */
960
- _debugSqlPreview(sql) {
961
- return sql
962
- .replace(/\s+/g, " ")
963
- .trim()
964
- .slice(0, 500);
965
- }
966
- /**
967
- * Runs query sql with process list comment.
968
- * @param {string} sql - SQL string.
969
- * @param {QueryOptions} options - Query options.
970
- * @returns {string} - SQL string with a leading process-list comment when annotations exist.
971
- */
972
- _querySqlWithProcessListComment(sql, options) {
973
- if (options.processListComment === false)
974
- return sql;
975
- const parts = [];
976
- if (this._connectionCheckoutName) {
977
- parts.push(`checkout="${this._processListCommentValue(this._connectionCheckoutName)}"`);
978
- }
979
- const annotations = getDatabaseAnnotations();
980
- if (annotations.length > 0) {
981
- parts.push(`annotations="${this._processListCommentValue(annotations.join(" > "))}"`);
982
- }
983
- if (parts.length === 0)
984
- return sql;
985
- return `/* velocious ${parts.join(" ")} */ ${sql}`;
986
- }
987
- /**
988
- * Runs process list comment value.
989
- * @param {string} value - Raw process-list comment value.
990
- * @returns {string} - Sanitized process-list comment value.
991
- */
992
- _processListCommentValue(value) {
993
- let sanitized = "";
994
- for (const character of value) {
995
- const codePoint = character.codePointAt(0);
996
- sanitized += codePoint !== undefined && (codePoint < 32 || codePoint === 127) ? " " : character;
997
- }
998
- return sanitized
999
- .replace(/\*\//g, "* /")
1000
- .replace(/\s+/g, " ")
1001
- .trim()
1002
- .slice(0, 200)
1003
- .replace(/"/g, "'");
1004
- }
1005
- /**
1006
- * Runs schema cache invalidating sql.
1007
- * @param {string} sql - SQL string.
1008
- * @returns {boolean} - Whether the SQL should invalidate schema metadata.
1009
- */
1010
- _schemaCacheInvalidatingSql(sql) {
1011
- const normalized = sql
1012
- .trim()
1013
- .replace(/^\ufeff/, "")
1014
- .replace(/\/\*[\s\S]*?\*\//g, " ")
1015
- .replace(/--[^\n]*(\n|$)/g, " ")
1016
- .replace(/\s+/g, " ")
1017
- .toLowerCase();
1018
- if (!normalized)
1019
- return false;
1020
- if (/^(create|alter|drop|rename)\b/.test(normalized))
1021
- return true;
1022
- if (/^comment\s+on\b/.test(normalized))
1023
- return true;
1024
- if (/^exec(?:ute)?\s+sp_rename\b/.test(normalized))
1025
- return true;
1026
- if (/^if\b[\s\S]*\bbegin\s+(create|alter|drop|rename)\b/.test(normalized))
1027
- return true;
1028
- return false;
1029
- }
1030
- /**
1031
- * Runs query logging enabled.
1032
- * @returns {boolean} - Whether query logging is enabled for this driver.
1033
- */
1034
- _queryLoggingEnabled() {
1035
- if (typeof this.configuration?.getQueryLoggingEnabled !== "function")
1036
- return true;
1037
- if (!this.configuration.getQueryLoggingEnabled())
1038
- return false;
1039
- const logger = new Logger("SQL", { configuration: this.configuration });
1040
- return logger.isLevelEnabled("info");
1041
- }
1042
- /**
1043
- * Runs log query.
1044
- * @param {object} args - Options object.
1045
- * @param {number} args.elapsedMs - Elapsed milliseconds.
1046
- * @param {string} args.logName - Query log subject.
1047
- * @param {string | undefined} args.sourceStack - Source stack.
1048
- * @param {string} args.sql - SQL string.
1049
- * @returns {Promise<void>} - Resolves when complete.
1050
- */
1051
- async _logQuery({ elapsedMs, logName, sourceStack, sql }) {
1052
- const logger = new Logger(logName, { configuration: this.configuration });
1053
- const sourceLine = this._querySourceLine(sourceStack);
1054
- const message = sourceLine
1055
- ? `(${formatElapsedMs(elapsedMs)}) ${sql}\n ↳ ${sourceLine}`
1056
- : `(${formatElapsedMs(elapsedMs)}) ${sql}`;
1057
- await logger.info(message);
1058
- }
1059
- /**
1060
- * Runs query source line.
1061
- * @param {string | undefined} sourceStack - Source stack.
1062
- * @returns {string | undefined} - Source line when an application frame is available.
1063
- */
1064
- _querySourceLine(sourceStack) {
1065
- if (!sourceStack)
1066
- return undefined;
1067
- const applicationDirectory = typeof this.configuration?.getDirectoryIfAvailable === "function"
1068
- ? this.configuration.getDirectoryIfAvailable()
1069
- : this.configuration?.getDirectory?.();
1070
- if (!applicationDirectory)
1071
- return undefined;
1072
- const error = new Error("Query source");
1073
- error.stack = sourceStack;
1074
- return BacktraceCleaner.getApplicationSourceLine(error, {
1075
- applicationDirectory,
1076
- frameworkSourceDirectory: this.configuration.getEnvironmentHandler().getFrameworkSourceDirectory()
1077
- });
1078
- }
1079
- /**
1080
- * Runs query actual.
1081
- * @abstract
1082
- * @param {string} sql - SQL string.
1083
- * @returns {Promise<QueryResultType>} - Resolves with the query actual.
1084
- */
1085
- _queryActual(sql) {
1086
- throw new Error(`queryActual not implemented`);
1087
- }
1088
- /**
1089
- * Runs query to sql.
1090
- * @abstract
1091
- * @param {Query} _query - Query instance.
1092
- * @returns {string} - SQL string.
1093
- */
1094
- queryToSql(_query) { throw new Error("queryToSql not implemented"); }
1095
- /**
1096
- * Runs retryable database error.
1097
- * @param {Error} _error - Error instance.
1098
- * @returns {RetryableDatabaseErrorResult} - Retry info.
1099
- */
1100
- retryableDatabaseError(_error) {
1101
- return { retry: false, reconnect: false };
1102
- }
1103
- /**
1104
- * Runs assert writable query.
1105
- * @param {string} sql - SQL string.
1106
- * @returns {void} - No return value.
1107
- */
1108
- _assertWritableQuery(sql) {
1109
- if (!this.isReadOnly())
1110
- return;
1111
- if (!this._sqlLooksLikeWrite(sql))
1112
- return;
1113
- throw new Error("Database is read-only");
1114
- }
1115
- /**
1116
- * Runs assert not read only.
1117
- * @returns {void} - No return value.
1118
- */
1119
- _assertNotReadOnly() {
1120
- if (this.isReadOnly()) {
1121
- throw new Error("Database is read-only");
1482
+
1483
+ if (truncateErrors.length == 0) {
1484
+ break
1485
+ } else if (tries <= 5) {
1486
+ // A truncate failed — the schema cache may still list a table that was
1487
+ // dropped out from under us (e.g. a db:rollback test that left the
1488
+ // shared DB rolled back). Clear it so the next pass re-reads the live
1489
+ // table list and no longer tries to truncate a table that is gone.
1490
+ this.clearSchemaCache()
1491
+ } else {
1492
+ throw truncateErrors[0]
1122
1493
  }
1123
- }
1124
- /**
1125
- * Runs sql looks like write.
1126
- * @param {string} sql - SQL string.
1127
- * @returns {boolean} - SQL representation.
1128
- */
1129
- _sqlLooksLikeWrite(sql) {
1130
- const normalized = sql.trim().toLowerCase();
1131
- if (!normalized)
1132
- return false;
1133
- if (normalized.startsWith("select") ||
1134
- normalized.startsWith("show") ||
1135
- normalized.startsWith("pragma") ||
1136
- normalized.startsWith("explain") ||
1137
- normalized.startsWith("describe")) {
1138
- return false;
1139
- }
1140
- if (normalized.startsWith("with")) {
1141
- const withMatch = normalized.match(/^\s*with[\s\S]+?\)\s*(select|insert|update|delete|merge|replace)\b/);
1142
- if (withMatch) {
1143
- return withMatch[1] !== "select";
1144
- }
1145
- return false;
1146
- }
1147
- const keywordMatch = normalized.match(/^\s*(\w+)/);
1148
- const keyword = keywordMatch ? keywordMatch[1] : "";
1149
- return [
1150
- "insert",
1151
- "update",
1152
- "delete",
1153
- "create",
1154
- "alter",
1155
- "drop",
1156
- "truncate",
1157
- "merge",
1158
- "replace"
1159
- ].includes(keyword);
1160
- }
1161
- /**
1162
- * Runs is read only.
1163
- * @returns {boolean} - Whether read only.
1164
- */
1165
- isReadOnly() {
1166
- return Boolean(this.getArgs().readOnly);
1167
- }
1168
- /**
1169
- * Runs rollback transaction.
1170
- * @returns {Promise<void>} - Resolves when complete.
1171
- */
1172
- async rollbackTransaction() {
1173
- await this._transactionsActionsMutex.sync(async () => {
1174
- try {
1175
- await this._rollbackTransactionAction();
1176
- }
1177
- finally {
1178
- this._transactionsCount--;
1179
- // A rolled-back transaction may have reverted DDL (e.g. a CREATE TABLE
1180
- // run lazily inside the transaction), so any cached schema metadata is
1181
- // now stale and must be invalidated. Without this, a later tableExists()
1182
- // check can report a table that the rollback already removed, so callers
1183
- // skip recreating it and then fail with "no such table".
1184
- this.clearSchemaCache();
1185
- }
1186
- });
1187
- }
1188
- /**
1189
- * Runs rollback transaction action.
1190
- * @returns {Promise<void>} - Resolves when complete.
1191
- */
1192
- async _rollbackTransactionAction() {
1193
- await this.query("ROLLBACK");
1194
- }
1195
- /**
1196
- * Runs generate save point name.
1197
- * @returns {string} - The generate save point name.
1198
- */
1199
- generateSavePointName() {
1200
- return `sp${new UUID(4).format().replaceAll("-", "")}`;
1201
- }
1202
- /**
1203
- * Runs start save point.
1204
- * @param {string} savePointName - Save point name.
1205
- * @returns {Promise<void>} - Resolves when complete.
1206
- */
1207
- async startSavePoint(savePointName) {
1208
- await this._transactionsActionsMutex.sync(async () => {
1209
- await this._startSavePointAction(savePointName);
1210
- });
1211
- }
1212
- /**
1213
- * Runs start save point action.
1214
- * @param {string} savePointName - Save point name.
1215
- * @returns {Promise<void>} - Resolves when complete.
1216
- */
1217
- async _startSavePointAction(savePointName) {
1218
- await this.query(`SAVEPOINT ${savePointName}`);
1219
- }
1220
- /**
1221
- * Runs rename column.
1222
- * @param {string} tableName - Table name.
1223
- * @param {string} oldColumnName - Previous column name.
1224
- * @param {string} newColumnName - New column name.
1225
- * @returns {Promise<void>} - Resolves when complete.
1226
- */
1227
- async renameColumn(tableName, oldColumnName, newColumnName) {
1228
- this._assertNotReadOnly();
1229
- const tableColumn = new TableColumn(oldColumnName);
1230
- tableColumn.setNewName(newColumnName);
1231
- const tableData = new TableData(tableName);
1232
- tableData.addColumn(tableColumn);
1233
- const alterTableSQLs = await this.alterTableSQLs(tableData);
1234
- for (const alterTableSQL of alterTableSQLs) {
1235
- await this.query(alterTableSQL);
1236
- }
1237
- }
1238
- /**
1239
- * Runs release save point.
1240
- * @param {string} savePointName - Save point name.
1241
- * @returns {Promise<void>} - Resolves when complete.
1242
- */
1243
- async releaseSavePoint(savePointName) {
1244
- await this._transactionsActionsMutex.sync(async () => {
1245
- await this._releaseSavePointAction(savePointName);
1246
- });
1247
- }
1248
- /**
1249
- * Runs release save point action.
1250
- * @param {string} savePointName - Save point name.
1251
- * @returns {Promise<void>} - Resolves when complete.
1252
- */
1253
- async _releaseSavePointAction(savePointName) {
1254
- try {
1255
- await this.query(`RELEASE SAVEPOINT ${savePointName}`);
1256
- }
1257
- catch (error) {
1258
- const message = error instanceof Error ? error.message : `${error}`;
1259
- // Savepoint may already be gone if the database rolled back automatically
1260
- if (message.toLowerCase().includes("savepoint") && message.toLowerCase().includes("does not exist")) {
1261
- this.logger.debug(`Release savepoint ignored because it no longer exists: ${savePointName}`);
1262
- return;
1263
- }
1264
- throw error;
1265
- }
1266
- }
1267
- /**
1268
- * Runs rollback save point.
1269
- * @param {string} savePointName - Save point name.
1270
- * @returns {Promise<void>} - Resolves when complete.
1271
- */
1272
- async rollbackSavePoint(savePointName) {
1273
- await this._transactionsActionsMutex.sync(async () => {
1274
- await this._rollbackSavePointAction(savePointName);
1275
- });
1276
- }
1277
- /**
1278
- * Runs rollback save point action.
1279
- * @param {string} savePointName - Save point name.
1280
- * @returns {Promise<void>} - Resolves when complete.
1281
- */
1282
- async _rollbackSavePointAction(savePointName) {
1283
- await this.query(`ROLLBACK TO SAVEPOINT ${savePointName}`);
1284
- }
1285
- /**
1286
- * Runs truncate all tables.
1287
- * @returns {Promise<void>} - Resolves when complete.
1288
- */
1289
- async truncateAllTables() {
1290
- this._assertNotReadOnly();
1291
- await this.withDisabledForeignKeys(async () => {
1292
- let tries = 0;
1293
- while (tries <= 5) {
1294
- tries++;
1295
- const tables = await this.getTables();
1296
- const truncateErrors = [];
1297
- for (const table of tables) {
1298
- if (table.getName() != "schema_migrations") {
1299
- try {
1300
- await table.truncate({ cascade: true });
1301
- }
1302
- catch (error) {
1303
- console.error(error);
1304
- truncateErrors.push(error);
1305
- }
1306
- }
1307
- }
1308
- if (truncateErrors.length == 0) {
1309
- break;
1310
- }
1311
- else if (tries <= 5) {
1312
- // A truncate failed — the schema cache may still list a table that was
1313
- // dropped out from under us (e.g. a db:rollback test that left the
1314
- // shared DB rolled back). Clear it so the next pass re-reads the live
1315
- // table list and no longer tries to truncate a table that is gone.
1316
- this.clearSchemaCache();
1317
- }
1318
- else {
1319
- throw truncateErrors[0];
1320
- }
1321
- }
1322
- });
1323
- }
1324
- /**
1325
- * Runs update.
1326
- * @param {UpdateSqlArgsType} args - Options object.
1327
- * @returns {Promise<void>} - Resolves when complete.
1328
- */
1329
- async update(args) {
1330
- this._assertNotReadOnly();
1331
- const sql = this.updateSql(args);
1332
- await this.query(sql);
1333
- }
1334
- /**
1335
- * Runs update sql.
1336
- * @abstract
1337
- * @param {UpdateSqlArgsType} args - Options object.
1338
- * @returns {string} - SQL string.
1339
- */
1340
- updateSql(args) {
1341
- throw new Error("'disableForeignKeys' not implemented");
1342
- }
1343
- /**
1344
- * Runs upsert sql.
1345
- * @abstract
1346
- * @param {UpsertSqlArgsType} args - Options object.
1347
- * @returns {string} - SQL string.
1348
- */
1349
- upsertSql(args) {
1350
- throw new Error("'upsertSql' not implemented");
1351
- }
1352
- /**
1353
- * Runs disable foreign keys.
1354
- * @abstract
1355
- * @returns {Promise<void>} - Resolves when complete.
1356
- */
1357
- disableForeignKeys() {
1358
- throw new Error("'disableForeignKeys' not implemented");
1359
- }
1360
- /**
1361
- * Runs enable foreign keys.
1362
- * @abstract
1363
- * @returns {Promise<void>} - Resolves when complete.
1364
- */
1365
- enableForeignKeys() {
1366
- throw new Error("'enableForeignKeys' not implemented");
1367
- }
1368
- /**
1369
- * Runs with disabled foreign keys.
1370
- * @param {function() : void} callback - Callback function.
1371
- * @returns {Promise<?>} - Resolves with the with disabled foreign keys.
1372
- */
1373
- async withDisabledForeignKeys(callback) {
1374
- await this.disableForeignKeys();
1375
- try {
1376
- return await callback();
1377
- }
1378
- finally {
1379
- await this.enableForeignKeys();
1380
- }
1381
- }
1382
- /**
1383
- * Blocks until a named advisory lock is acquired on this connection.
1384
- * Advisory locks are connection-scoped and do not interact with row or
1385
- * table locks; they are purely cooperative between callers that use the
1386
- * same name and let you serialize functionality without blocking readers
1387
- * or writers that do not participate in the same lock.
1388
- * @abstract
1389
- * @param {string} name - Lock name.
1390
- * @param {{timeoutMs?: number | null}} [_args] - Optional timeout in milliseconds; `null` or undefined blocks forever.
1391
- * @returns {Promise<boolean>} - Resolves to true when the lock has been acquired, false if the timeout elapsed.
1392
- */
1393
- acquireAdvisoryLock(name, _args = {}) {
1394
- throw new Error(`'acquireAdvisoryLock' not implemented for ${this.constructor.name}`);
1395
- }
1396
- /**
1397
- * Attempts to acquire a named advisory lock without blocking.
1398
- * @abstract
1399
- * @param {string} name - Lock name.
1400
- * @returns {Promise<boolean>} - Resolves to true if the lock was acquired, false if it was already held.
1401
- */
1402
- tryAcquireAdvisoryLock(name) {
1403
- throw new Error(`'tryAcquireAdvisoryLock' not implemented for ${this.constructor.name}`);
1404
- }
1405
- /**
1406
- * Releases a named advisory lock previously acquired on this connection.
1407
- * @abstract
1408
- * @param {string} name - Lock name.
1409
- * @returns {Promise<boolean>} - Resolves to true if the lock was held by this session and has now been released.
1410
- */
1411
- releaseAdvisoryLock(name) {
1412
- throw new Error(`'releaseAdvisoryLock' not implemented for ${this.constructor.name}`);
1413
- }
1414
- /**
1415
- * Checks whether a named advisory lock is currently held by any session.
1416
- * Intended as an introspection helper; callers who need to act on the
1417
- * result should prefer `tryAcquireAdvisoryLock` to avoid a TOCTOU race.
1418
- * @abstract
1419
- * @param {string} name - Lock name.
1420
- * @returns {Promise<boolean>} - Resolves to true if the lock is held by ? session.
1421
- */
1422
- isAdvisoryLockHeld(name) {
1423
- throw new Error(`'isAdvisoryLockHeld' not implemented for ${this.constructor.name}`);
1424
- }
1494
+ }
1495
+ })
1496
+ }
1497
+
1498
+ /**
1499
+ * Runs update.
1500
+ * @param {UpdateSqlArgsType} args - Options object.
1501
+ * @returns {Promise<void>} - Resolves when complete.
1502
+ */
1503
+ async update(args) {
1504
+ this._assertNotReadOnly()
1505
+ const sql = this.updateSql(args)
1506
+
1507
+ await this.query(sql)
1508
+ }
1509
+
1510
+ /**
1511
+ * Runs update sql.
1512
+ * @abstract
1513
+ * @param {UpdateSqlArgsType} args - Options object.
1514
+ * @returns {string} - SQL string.
1515
+ */
1516
+ updateSql(args) { // eslint-disable-line no-unused-vars
1517
+ throw new Error("'disableForeignKeys' not implemented")
1518
+ }
1519
+
1520
+ /**
1521
+ * Runs upsert sql.
1522
+ * @abstract
1523
+ * @param {UpsertSqlArgsType} args - Options object.
1524
+ * @returns {string} - SQL string.
1525
+ */
1526
+ upsertSql(args) { // eslint-disable-line no-unused-vars
1527
+ throw new Error("'upsertSql' not implemented")
1528
+ }
1529
+
1530
+ /**
1531
+ * Runs disable foreign keys.
1532
+ * @abstract
1533
+ * @returns {Promise<void>} - Resolves when complete.
1534
+ */
1535
+ disableForeignKeys() {
1536
+ throw new Error("'disableForeignKeys' not implemented")
1537
+ }
1538
+
1539
+ /**
1540
+ * Runs enable foreign keys.
1541
+ * @abstract
1542
+ * @returns {Promise<void>} - Resolves when complete.
1543
+ */
1544
+ enableForeignKeys() {
1545
+ throw new Error("'enableForeignKeys' not implemented")
1546
+ }
1547
+
1548
+ /**
1549
+ * Runs with disabled foreign keys.
1550
+ * @param {function() : void} callback - Callback function.
1551
+ * @returns {Promise<?>} - Resolves with the with disabled foreign keys.
1552
+ */
1553
+ async withDisabledForeignKeys(callback) {
1554
+ await this.disableForeignKeys()
1555
+
1556
+ try {
1557
+ return await callback()
1558
+ } finally {
1559
+ await this.enableForeignKeys()
1560
+ }
1561
+ }
1562
+
1563
+ /**
1564
+ * Blocks until a named advisory lock is acquired on this connection.
1565
+ * Advisory locks are connection-scoped and do not interact with row or
1566
+ * table locks; they are purely cooperative between callers that use the
1567
+ * same name and let you serialize functionality without blocking readers
1568
+ * or writers that do not participate in the same lock.
1569
+ * @abstract
1570
+ * @param {string} name - Lock name.
1571
+ * @param {{timeoutMs?: number | null}} [_args] - Optional timeout in milliseconds; `null` or undefined blocks forever.
1572
+ * @returns {Promise<boolean>} - Resolves to true when the lock has been acquired, false if the timeout elapsed.
1573
+ */
1574
+ acquireAdvisoryLock(name, _args = {}) {
1575
+ throw new Error(`'acquireAdvisoryLock' not implemented for ${this.constructor.name}`)
1576
+ }
1577
+
1578
+ /**
1579
+ * Attempts to acquire a named advisory lock without blocking.
1580
+ * @abstract
1581
+ * @param {string} name - Lock name.
1582
+ * @returns {Promise<boolean>} - Resolves to true if the lock was acquired, false if it was already held.
1583
+ */
1584
+ tryAcquireAdvisoryLock(name) { // eslint-disable-line no-unused-vars
1585
+ throw new Error(`'tryAcquireAdvisoryLock' not implemented for ${this.constructor.name}`)
1586
+ }
1587
+
1588
+ /**
1589
+ * Releases a named advisory lock previously acquired on this connection.
1590
+ * @abstract
1591
+ * @param {string} name - Lock name.
1592
+ * @returns {Promise<boolean>} - Resolves to true if the lock was held by this session and has now been released.
1593
+ */
1594
+ releaseAdvisoryLock(name) { // eslint-disable-line no-unused-vars
1595
+ throw new Error(`'releaseAdvisoryLock' not implemented for ${this.constructor.name}`)
1596
+ }
1597
+
1598
+ /**
1599
+ * Checks whether a named advisory lock is currently held by any session.
1600
+ * Intended as an introspection helper; callers who need to act on the
1601
+ * result should prefer `tryAcquireAdvisoryLock` to avoid a TOCTOU race.
1602
+ * @abstract
1603
+ * @param {string} name - Lock name.
1604
+ * @returns {Promise<boolean>} - Resolves to true if the lock is held by ? session.
1605
+ */
1606
+ isAdvisoryLockHeld(name) { // eslint-disable-line no-unused-vars
1607
+ throw new Error(`'isAdvisoryLockHeld' not implemented for ${this.constructor.name}`)
1608
+ }
1425
1609
  }
1426
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9kYXRhYmFzZS9kcml2ZXJzL2Jhc2UuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWTtBQUVaOzs7Ozs7OztHQVFHO0FBQ0g7Ozs7O0dBS0c7QUFDSDs7Ozs7R0FLRztBQUNIOzs7Ozs7Ozs7R0FTRztBQUNIOzs7O0dBSUc7QUFDSDs7Ozs7OztHQU9HO0FBQ0g7Ozs7Ozs7R0FPRztBQUVIOzs7Ozs7OztHQVFHO0FBRUg7Ozs7Ozs7Ozs7O0dBV0c7QUFFSDs7Ozs7OztHQU9HO0FBRUg7Ozs7OztHQU1HO0FBQ0g7Ozs7Ozs7R0FPRztBQUVILE9BQU8sZ0JBQWdCLE1BQU0sa0NBQWtDLENBQUE7QUFDL0QsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDMUQsT0FBTyxNQUFNLE1BQU0saUJBQWlCLENBQUE7QUFDcEMsT0FBTyxLQUFLLE1BQU0sbUJBQW1CLENBQUE7QUFDckMsT0FBTyxPQUFPLE1BQU0sZUFBZSxDQUFBO0FBQ25DLE9BQU8sS0FBSyxNQUFNLDJCQUEyQixDQUFBO0FBQzdDLE9BQU8sUUFBUSxNQUFNLFVBQVUsQ0FBQTtBQUMvQixPQUFPLElBQUksTUFBTSxXQUFXLENBQUE7QUFDNUIsT0FBTyxTQUFTLE1BQU0sd0JBQXdCLENBQUE7QUFDOUMsT0FBTyxXQUFXLE1BQU0sK0JBQStCLENBQUE7QUFDdkQsT0FBTyxlQUFlLE1BQU0sb0NBQW9DLENBQUE7QUFDaEUsT0FBTyxJQUFJLE1BQU0sd0JBQXdCLENBQUE7QUFFekM7OztHQUdHO0FBQ0gsU0FBUyxLQUFLO0lBQ1osSUFBSSxVQUFVLENBQUMsV0FBVyxJQUFJLE9BQU8sVUFBVSxDQUFDLFdBQVcsQ0FBQyxHQUFHLElBQUksVUFBVSxFQUFFLENBQUM7UUFDOUUsT0FBTyxVQUFVLENBQUMsV0FBVyxDQUFDLEdBQUcsRUFBRSxDQUFBO0lBQ3JDLENBQUM7SUFFRCxP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LENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQTtJQUN2RixDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCxzQkFBc0IsQ0FBQyxJQUFJO1FBQ3pCLE1BQU0sSUFBSSxLQUFLLENBQUMsZ0RBQWdELElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQTtJQUMxRixDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCxtQkFBbUIsQ0FBQyxJQUFJO1FBQ3RCLE1BQU0sSUFBSSxLQUFLLENBQUMsNkNBQTZDLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQTtJQUN2RixDQUFDO0lBRUQ7Ozs7Ozs7T0FPRztJQUNILGtCQUFrQixDQUFDLElBQUk7UUFDckIsTUFBTSxJQUFJLEtBQUssQ0FBQyw0Q0FBNEMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFBO0lBQ3RGLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8vIEB0cy1jaGVja1xuXG4vKipcbiAqIENyZWF0ZUluZGV4U3FsQXJncyB0eXBlLlxuICogQHR5cGVkZWYge29iamVjdH0gQ3JlYXRlSW5kZXhTcWxBcmdzXG4gKiBAcHJvcGVydHkge0FycmF5PHN0cmluZyB8IGltcG9ydChcIi4vLi4vdGFibGUtZGF0YS90YWJsZS1jb2x1bW4uanNcIikuZGVmYXVsdD59IGNvbHVtbnMgLSBDb2x1bW5zIHRvIGluY2x1ZGUgaW4gdGhlIGluZGV4LlxuICogQHByb3BlcnR5IHtib29sZWFufSBbaWZOb3RFeGlzdHNdIC0gU2tpcCBjcmVhdGlvbiBpZiB0aGUgaW5kZXggYWxyZWFkeSBleGlzdHMuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gW25hbWVdIC0gRXhwbGljaXQgaW5kZXggbmFtZSB0byB1c2UuXG4gKiBAcHJvcGVydHkge2Jvb2xlYW59IFt1bmlxdWVdIC0gV2hldGhlciB0aGUgaW5kZXggc2hvdWxkIGVuZm9yY2UgdW5pcXVlbmVzcy5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSB0YWJsZU5hbWUgLSBOYW1lIG9mIHRoZSB0YWJsZSB0byBhZGQgdGhlIGluZGV4IHRvLlxuICovXG4vKipcbiAqIERyb3BUYWJsZVNxbEFyZ3NUeXBlIHR5cGUuXG4gKiBAdHlwZWRlZiB7b2JqZWN0fSBEcm9wVGFibGVTcWxBcmdzVHlwZVxuICogQHByb3BlcnR5IHtib29sZWFufSBbY2FzY2FkZV0gLSBXaGV0aGVyIGRlcGVuZGVudCBvYmplY3RzIHNob3VsZCBiZSBkcm9wcGVkIHRvby5cbiAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0gW2lmRXhpc3RzXSAtIFNraXAgZHJvcHBpbmcgaWYgdGhlIHRhYmxlIGRvZXMgbm90IGV4aXN0LlxuICovXG4vKipcbiAqIERlbGV0ZVNxbEFyZ3NUeXBlIHR5cGUuXG4gKiBAdHlwZWRlZiB7b2JqZWN0fSBEZWxldGVTcWxBcmdzVHlwZVxuICogQHByb3BlcnR5IHtzdHJpbmd9IHRhYmxlTmFtZSAtIFRhYmxlIG5hbWUgdG8gZGVsZXRlIGZyb20uXG4gKiBAcHJvcGVydHkge3tba2V5OiBzdHJpbmddOiA/fX0gY29uZGl0aW9ucyAtIENvbmRpdGlvbnMgdXNlZCB0byBidWlsZCB0aGUgZGVsZXRlIFdIRVJFIGNsYXVzZS5cbiAqL1xuLyoqXG4gKiBJbnNlcnRTcWxBcmdzVHlwZSB0eXBlLlxuICogQHR5cGVkZWYge29iamVjdH0gSW5zZXJ0U3FsQXJnc1R5cGVcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nW119IFtjb2x1bW5zXSAtIENvbHVtbiBuYW1lcyBmb3IgYHJvd3NgIGluc2VydHMuXG4gKiBAcHJvcGVydHkge3tba2V5OiBzdHJpbmddOiA/fX0gW2RhdGFdIC0gQ29sdW1uL3ZhbHVlIHBhaXJzIGZvciBhIHNpbmdsZS1yb3cgaW5zZXJ0LlxuICogQHByb3BlcnR5IHtib29sZWFufSBbbXVsdGlwbGVdIC0gV2hldGhlciB0aGlzIGluc2VydCBzaG91bGQgYmUgdHJlYXRlZCBhcyBtdWx0aS1yb3cuXG4gKiBAcHJvcGVydHkge3N0cmluZ1tdfSBbcmV0dXJuTGFzdEluc2VydGVkQ29sdW1uTmFtZXNdIC0gQ29sdW1uIG5hbWVzIHRvIHJldHVybiBhZnRlciBpbnNlcnQuXG4gKiBAcHJvcGVydHkge0FycmF5PEFycmF5PD8+Pn0gW3Jvd3NdIC0gUm93IHZhbHVlcyBmb3IgYSBtdWx0aS1yb3cgaW5zZXJ0LlxuICogQHByb3BlcnR5IHtzdHJpbmd9IHRhYmxlTmFtZSAtIFRhYmxlIG5hbWUgdG8gaW5zZXJ0IGludG8uXG4gKi9cbi8qKlxuICogUXVlcnlSb3dUeXBlIHR5cGUuXG4gKiBAdHlwZWRlZiB7UmVjb3JkPHN0cmluZywgPz59IFF1ZXJ5Um93VHlwZVxuICogQHR5cGVkZWYge0FycmF5PFF1ZXJ5Um93VHlwZT59IFF1ZXJ5UmVzdWx0VHlwZVxuICovXG4vKipcbiAqIFJldHJ5YWJsZURhdGFiYXNlRXJyb3JSZXN1bHQgdHlwZS5cbiAqIEB0eXBlZGVmIHtvYmplY3R9IFJldHJ5YWJsZURhdGFiYXNlRXJyb3JSZXN1bHRcbiAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0gcmV0cnkgLSBXaGV0aGVyIHRoZSBlcnJvciBzaG91bGQgYmUgcmV0cmllZC5cbiAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0gcmVjb25uZWN0IC0gV2hldGhlciB0byByZWNvbm5lY3QgYmVmb3JlIHJldHJ5aW5nLlxuICogQHByb3BlcnR5IHtudW1iZXJ9IFttYXhUcmllc10gLSBPdmVycmlkZSB0aGUgbWF4IHJldHJ5IGF0dGVtcHRzLlxuICogQHByb3BlcnR5IHtudW1iZXJ9IFt3YWl0TXNdIC0gV2FpdCB0aW1lIGJlZm9yZSByZXRyeWluZyBpbiBtaWxsaXNlY29uZHMuXG4gKi9cbi8qKlxuICogUXVlcnlPcHRpb25zIHR5cGUuXG4gKiBAdHlwZWRlZiB7b2JqZWN0fSBRdWVyeU9wdGlvbnNcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBbbG9nTmFtZV0gLSBRdWVyeSBsb2cgc3ViamVjdC5cbiAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0gW2xvZ1F1ZXJ5XSAtIFdoZXRoZXIgdG8gbG9nIHRoZSBxdWVyeS5cbiAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0gW3Byb2Nlc3NMaXN0Q29tbWVudF0gLSBXaGV0aGVyIHRvIGFkZCBwcm9jZXNzLWxpc3QgY29tbWVudHMgdG8gdGhlIHF1ZXJ5LlxuICogQHByb3BlcnR5IHtzdHJpbmd9IFtzb3VyY2VTdGFja10gLSBTdGFjayBjYXB0dXJlZCBhdCB0aGUgY2FsbGVyIGJvdW5kYXJ5LlxuICovXG5cbi8qKlxuICogQWN0aXZlUXVlcnlEZWJ1Z1NuYXBzaG90IHR5cGUuXG4gKiBAdHlwZWRlZiB7b2JqZWN0fSBBY3RpdmVRdWVyeURlYnVnU25hcHNob3RcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nW119IGFubm90YXRpb25zIC0gRGF0YWJhc2UgYW5ub3RhdGlvbnMgYWN0aXZlIHdoZW4gdGhlIHF1ZXJ5IHN0YXJ0ZWQuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gbG9nTmFtZSAtIFF1ZXJ5IGxvZyBuYW1lLlxuICogQHByb3BlcnR5IHtudW1iZXJ9IHN0YXJ0ZWRBdFVuaXhNcyAtIFF1ZXJ5IHN0YXJ0IHRpbWVzdGFtcC5cbiAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBydW5uaW5nTXMgLSBRdWVyeSBydW50aW1lIGluIG1pbGxpc2Vjb25kcy5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBzcWxQcmV2aWV3IC0gVHJ1bmNhdGVkIFNRTCBwcmV2aWV3LlxuICovXG5cbi8qKlxuICogRGF0YWJhc2VDb25uZWN0aW9uRGVidWdTbmFwc2hvdCB0eXBlLlxuICogQHR5cGVkZWYge29iamVjdH0gRGF0YWJhc2VDb25uZWN0aW9uRGVidWdTbmFwc2hvdFxuICogQHByb3BlcnR5IHtBY3RpdmVRdWVyeURlYnVnU25hcHNob3QgfCBudWxsfSBhY3RpdmVRdWVyeSAtIEN1cnJlbnRseSBydW5uaW5nIHF1ZXJ5LCBpZiBhbnkuXG4gKiBAcHJvcGVydHkge251bWJlciB8IHVuZGVmaW5lZH0gY2hlY2tlZE91dEF0VW5peE1zIC0gQ2hlY2tvdXQgc3RhcnQgdGltZXN0YW1wIGZvciBhY3RpdmUgY2hlY2tvdXRzLlxuICogQHByb3BlcnR5IHtudW1iZXIgfCB1bmRlZmluZWR9IGNoZWNrb3V0QWdlTXMgLSBBY3RpdmUgY2hlY2tvdXQgYWdlIGluIG1pbGxpc2Vjb25kcy5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nIHwgdW5kZWZpbmVkfSBjaGVja291dE5hbWUgLSBIdW1hbi1yZWFkYWJsZSBjaGVja291dCBuYW1lLlxuICogQHByb3BlcnR5IHtzdHJpbmd9IGRyaXZlckNsYXNzIC0gRHJpdmVyIGNsYXNzIG5hbWUuXG4gKiBAcHJvcGVydHkge251bWJlciB8IHVuZGVmaW5lZH0gaWRTZXEgLSBQb29sIGNoZWNrb3V0IElEIHNlcXVlbmNlLlxuICogQHByb3BlcnR5IHtudW1iZXJ9IG9wZW5UcmFuc2FjdGlvbnMgLSBOdW1iZXIgb2Ygb3BlbiB0cmFuc2FjdGlvbiBmcmFtZXMuXG4gKiBAcHJvcGVydHkge251bWJlcn0gc2NoZW1hQ2FjaGVFbnRyaWVzIC0gTnVtYmVyIG9mIGNhY2hlZCBzY2hlbWEgbWV0YWRhdGEgZW50cmllcy5cbiAqL1xuXG4vKipcbiAqIEFjdGl2ZVF1ZXJ5U3RhdGUgdHlwZS5cbiAqIEB0eXBlZGVmIHtvYmplY3R9IEFjdGl2ZVF1ZXJ5U3RhdGVcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nW119IGFubm90YXRpb25zIC0gRGF0YWJhc2UgYW5ub3RhdGlvbnMgYWN0aXZlIHdoZW4gdGhlIHF1ZXJ5IHN0YXJ0ZWQuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gbG9nTmFtZSAtIFF1ZXJ5IGxvZyBuYW1lLlxuICogQHByb3BlcnR5IHtudW1iZXJ9IHN0YXJ0ZWRBdFVuaXhNcyAtIFF1ZXJ5IHN0YXJ0IHRpbWVzdGFtcC5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBzcWxQcmV2aWV3IC0gVHJ1bmNhdGVkIFNRTCBwcmV2aWV3LlxuICovXG5cbi8qKlxuICogVXBkYXRlU3FsQXJnc1R5cGUgdHlwZS5cbiAqIEB0eXBlZGVmIHtvYmplY3R9VXBkYXRlU3FsQXJnc1R5cGVcbiAqIEBwcm9wZXJ0eSB7b2JqZWN0fSBjb25kaXRpb25zIC0gQ29uZGl0aW9ucyB1c2VkIHRvIGJ1aWxkIHRoZSB1cGRhdGUgV0hFUkUgY2xhdXNlLlxuICogQHByb3BlcnR5IHtvYmplY3R9IGRhdGEgLSBDb2x1bW4vdmFsdWUgcGFpcnMgdG8gdXBkYXRlLlxuICogQHByb3BlcnR5IHtzdHJpbmd9IHRhYmxlTmFtZSAtIFRhYmxlIG5hbWUgdG8gdXBkYXRlLlxuICovXG4vKipcbiAqIFVwc2VydFNxbEFyZ3NUeXBlIHR5cGUuXG4gKiBAdHlwZWRlZiB7b2JqZWN0fVVwc2VydFNxbEFyZ3NUeXBlXG4gKiBAcHJvcGVydHkge3N0cmluZ1tdfSBjb25mbGljdENvbHVtbnMgLSBDb2x1bW5zIHRoYXQgZGVmaW5lIGEgY29uZmxpY3QuXG4gKiBAcHJvcGVydHkge29iamVjdH0gZGF0YSAtIENvbHVtbi92YWx1ZSBwYWlycyB0byBpbnNlcnQuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gdGFibGVOYW1lIC0gVGFibGUgbmFtZSB0byB1cHNlcnQgaW50by5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nW119IHVwZGF0ZUNvbHVtbnMgLSBDb2x1bW5zIHRvIHVwZGF0ZSBvbiBjb25mbGljdC5cbiAqL1xuXG5pbXBvcnQgQmFja3RyYWNlQ2xlYW5lciBmcm9tIFwiLi4vLi4vdXRpbHMvYmFja3RyYWNlLWNsZWFuZXIuanNcIlxuaW1wb3J0IHsgZ2V0RGF0YWJhc2VBbm5vdGF0aW9ucyB9IGZyb20gXCIuLi9hbm5vdGF0aW9ucy5qc1wiXG5pbXBvcnQgTG9nZ2VyIGZyb20gXCIuLi8uLi9sb2dnZXIuanNcIlxuaW1wb3J0IFF1ZXJ5IGZyb20gXCIuLi9xdWVyeS9pbmRleC5qc1wiXG5pbXBvcnQgSGFuZGxlciBmcm9tIFwiLi4vaGFuZGxlci5qc1wiXG5pbXBvcnQgTXV0ZXggZnJvbSBcImVwaWMtbG9ja3MvYnVpbGQvbXV0ZXguanNcIlxuaW1wb3J0IHN0cmZ0aW1lIGZyb20gXCJzdHJmdGltZVwiXG5pbXBvcnQgVVVJRCBmcm9tIFwicHVyZS11dWlkXCJcbmltcG9ydCBUYWJsZURhdGEgZnJvbSBcIi4uL3RhYmxlLWRhdGEvaW5kZXguanNcIlxuaW1wb3J0IFRhYmxlQ29sdW1uIGZyb20gXCIuLi90YWJsZS1kYXRhL3RhYmxlLWNvbHVtbi5qc1wiXG5pbXBvcnQgVGFibGVGb3JlaWduS2V5IGZyb20gXCIuLi90YWJsZS1kYXRhL3RhYmxlLWZvcmVpZ24ta2V5LmpzXCJcbmltcG9ydCB3YWl0IGZyb20gXCJhd2FpdGVyeS9idWlsZC93YWl0LmpzXCJcblxuLyoqXG4gKiBSdW5zIG5vdyBtcy5cbiAqIEByZXR1cm5zIHtudW1iZXJ9IC0gQ3VycmVudCBoaWdoLXJlc29sdXRpb24taXNoIHRpbWVzdGFtcCBpbiBtaWxsaXNlY29uZHMuXG4gKi9cbmZ1bmN0aW9uIG5vd01zKCkge1xuICBpZiAoZ2xvYmFsVGhpcy5wZXJmb3JtYW5jZSAmJiB0eXBlb2YgZ2xvYmFsVGhpcy5wZXJmb3JtYW5jZS5ub3cgPT0gXCJmdW5jdGlvblwiKSB7XG4gICAgcmV0dXJuIGdsb2JhbFRoaXMucGVyZm9ybWFuY2Uubm93KClcbiAgfVxuXG4gIHJldHVybiBEYXRlLm5vdygpXG59XG5cbi8qKlxuICogUnVucyBmb3JtYXQgZWxhcHNlZCBtcy5cbiAqIEBwYXJhbSB7bnVtYmVyfSBlbGFwc2VkTXMgLSBFbGFwc2VkIG1pbGxpc2Vjb25kcy5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gRm9ybWF0dGVkIGVsYXBzZWQgbWlsbGlzZWNvbmRzLlxuICovXG5mdW5jdGlvbiBmb3JtYXRFbGFwc2VkTXMoZWxhcHNlZE1zKSB7XG4gIHJldHVybiBgJHtNYXRoLm1heChlbGFwc2VkTXMsIDApLnRvRml4ZWQoMSl9bXNgXG59XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFZlbG9jaW91c0RhdGFiYXNlRHJpdmVyc0Jhc2Uge1xuICAvKipcbiAgICogSWQgc2VxLlxuICAgIEB0eXBlIHtudW1iZXIgfCB1bmRlZmluZWR9ICovXG4gIGlkU2VxID0gdW5kZWZpbmVkXG4gIC8qKlxuICAgKiBOYXJyb3dzIHRoZSBydW50aW1lIHZhbHVlIHRvIHRoZSBkb2N1bWVudGVkIHR5cGUuXG4gICAgQHR5cGUge0FycmF5PEFycmF5PCgpID0+IHZvaWQgfCBQcm9taXNlPHZvaWQ+Pj59ICovXG4gIF9hZnRlckNvbW1pdENhbGxiYWNrRnJhbWVzXG4gIC8qKlxuICAgKiBOYXJyb3dzIHRoZSBydW50aW1lIHZhbHVlIHRvIHRoZSBkb2N1bWVudGVkIHR5cGUuXG4gICAgQHR5cGUge01hcDxzdHJpbmcsIFByb21pc2U8Pz4+fSAqL1xuICBfc2NoZW1hQ2FjaGVcbiAgLyoqXG4gICAqIE5hcnJvd3MgdGhlIHJ1bnRpbWUgdmFsdWUgdG8gdGhlIGRvY3VtZW50ZWQgdHlwZS5cbiAgICBAdHlwZSB7KCgpID0+IHZvaWQpIHwgdW5kZWZpbmVkfSAqL1xuICBfc2NoZW1hQ2FjaGVJbnZhbGlkYXRvclxuICAvKipcbiAgICogTmFycm93cyB0aGUgcnVudGltZSB2YWx1ZSB0byB0aGUgZG9jdW1lbnRlZCB0eXBlLlxuICAgIEB0eXBlIHtzdHJpbmcgfCB1bmRlZmluZWR9ICovXG4gIF9jb25uZWN0aW9uQ2hlY2tvdXROYW1lXG4gIC8qKlxuICAgKiBBY3RpdmUgcXVlcnkuXG4gICAgQHR5cGUge0FjdGl2ZVF1ZXJ5U3RhdGUgfCBudWxsfSAqL1xuICBfYWN0aXZlUXVlcnkgPSBudWxsXG5cbiAgLyoqXG4gICAqIFJ1bnMgY29uc3RydWN0b3IuXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vLi4vY29uZmlndXJhdGlvbi10eXBlcy5qc1wiKS5EYXRhYmFzZUNvbmZpZ3VyYXRpb25UeXBlfSBjb25maWcgLSBDb25maWd1cmF0aW9uIG9iamVjdC5cbiAgICogQHBhcmFtIHtpbXBvcnQoXCIuLi8uLi9jb25maWd1cmF0aW9uLmpzXCIpLmRlZmF1bHR9IGNvbmZpZ3VyYXRpb24gLSBDb25maWd1cmF0aW9uIGluc3RhbmNlLlxuICAgKi9cbiAgY29uc3RydWN0b3IoY29uZmlnLCBjb25maWd1cmF0aW9uKSB7XG4gICAgdGhpcy5fYXJncyA9IGNvbmZpZ1xuICAgIHRoaXMuY29uZmlndXJhdGlvbiA9IGNvbmZpZ3VyYXRpb25cbiAgICB0aGlzLm11dGV4ID0gbmV3IE11dGV4KCkgLy8gQ2FuIGJlIHVzZWQgdG8gbG9jayB0aGlzIGluc3RhbmNlIGZvciBleGNsdXNpdmUgdXNlXG4gICAgdGhpcy5sb2dnZXIgPSBuZXcgTG9nZ2VyKHRoaXMpXG4gICAgdGhpcy5fYWZ0ZXJDb21taXRDYWxsYmFja0ZyYW1lcyA9IFtdXG4gICAgdGhpcy5fdHJhbnNhY3Rpb25zQ291bnQgPSAwXG4gICAgdGhpcy5fdHJhbnNhY3Rpb25zQWN0aW9uc011dGV4ID0gbmV3IE11dGV4KClcbiAgICB0aGlzLl9zY2hlbWFDYWNoZSA9IG5ldyBNYXAoKVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgYWRkIGZvcmVpZ24ga2V5LlxuICAgKiBAcGFyYW0ge3N0cmluZ30gdGFibGVOYW1lIC0gVGFibGUgbmFtZS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGNvbHVtbk5hbWUgLSBDb2x1bW4gbmFtZS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHJlZmVyZW5jZWRUYWJsZU5hbWUgLSBSZWZlcmVuY2VkIHRhYmxlIG5hbWUuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSByZWZlcmVuY2VkQ29sdW1uTmFtZSAtIFJlZmVyZW5jZWQgY29sdW1uIG5hbWUuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gT3B0aW9ucyBvYmplY3QuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIHdoZW4gY29tcGxldGUuXG4gICAqL1xuICBhc3luYyBhZGRGb3JlaWduS2V5KHRhYmxlTmFtZSwgY29sdW1uTmFtZSwgcmVmZXJlbmNlZFRhYmxlTmFtZSwgcmVmZXJlbmNlZENvbHVtbk5hbWUsIGFyZ3MpIHtcbiAgICB0aGlzLl9hc3NlcnROb3RSZWFkT25seSgpXG4gICAgY29uc3QgdGFibGVGb3JlaWduS2V5QXJncyA9IE9iamVjdC5hc3NpZ24oXG4gICAgICB7XG4gICAgICAgIGNvbHVtbk5hbWUsXG4gICAgICAgIHRhYmxlTmFtZSxcbiAgICAgICAgcmVmZXJlbmNlZENvbHVtbk5hbWUsXG4gICAgICAgIHJlZmVyZW5jZWRUYWJsZU5hbWVcbiAgICAgIH0sXG4gICAgICBhcmdzXG4gICAgKVxuICAgIGNvbnN0IHRhYmxlRm9yZWlnbktleSA9IG5ldyBUYWJsZUZvcmVpZ25LZXkodGFibGVGb3JlaWduS2V5QXJncylcbiAgICBjb25zdCB0YWJsZURhdGEgPSBuZXcgVGFibGVEYXRhKHRhYmxlTmFtZSlcblxuICAgIHRhYmxlRGF0YS5hZGRGb3JlaWduS2V5KHRhYmxlRm9yZWlnbktleSlcblxuICAgIGNvbnN0IGFsdGVyVGFibGVTUUxzID0gYXdhaXQgdGhpcy5hbHRlclRhYmxlU1FMcyh0YWJsZURhdGEpXG5cbiAgICBmb3IgKGNvbnN0IGFsdGVyVGFibGVTUUwgb2YgYWx0ZXJUYWJsZVNRTHMpIHtcbiAgICAgIGF3YWl0IHRoaXMucXVlcnkoYWx0ZXJUYWJsZVNRTClcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUnVucyBhbHRlciB0YWJsZSBzcWxzLlxuICAgKiBAYWJzdHJhY3RcbiAgICogQHBhcmFtIHtpbXBvcnQoXCIuLi90YWJsZS1kYXRhL2luZGV4LmpzXCIpLmRlZmF1bHR9IF90YWJsZURhdGEgLSBUYWJsZSBkYXRhLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmdbXT59IC0gUmVzb2x2ZXMgd2l0aCBTUUwgc3RhdGVtZW50cy5cbiAgICovXG4gIGFsdGVyVGFibGVTUUxzKF90YWJsZURhdGEpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJhbHRlclRhYmxlU1FMcyBub3QgaW1wbGVtZW50ZWRcIilcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGNvbm5lY3QuXG4gICAqIEBhYnN0cmFjdFxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBSZXNvbHZlcyB3aGVuIGNvbXBsZXRlLlxuICAgKi9cbiAgY29ubmVjdCgpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCInY29ubmVjdCcgbm90IGltcGxlbWVudGVkXCIpXG4gIH1cblxuICAvKipcbiAgICogT3B0aW9uYWwgY2xvc2UgaG9vayBmb3IgZGF0YWJhc2UgZHJpdmVycy5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgd2hlbiBjb21wbGV0ZS5cbiAgICovXG4gIGFzeW5jIGNsb3NlKCkge1xuICAgIC8vIE5vLW9wIGJ5IGRlZmF1bHRcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHNldCBjb25uZWN0aW9uIGNoZWNrb3V0IG5hbWUuXG4gICAqIEBwYXJhbSB7c3RyaW5nIHwgdW5kZWZpbmVkfSBuYW1lIC0gSHVtYW4tcmVhZGFibGUgbmFtZSBmb3IgdGhpcyBhY3RpdmUgY2hlY2tvdXQuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIHdoZW4gY29tcGxldGUuXG4gICAqL1xuICBhc3luYyBzZXRDb25uZWN0aW9uQ2hlY2tvdXROYW1lKG5hbWUpIHtcbiAgICB0aGlzLl9jb25uZWN0aW9uQ2hlY2tvdXROYW1lID0gbmFtZVxuICAgIHRoaXMuX2Nvbm5lY3Rpb25DaGVja2VkT3V0QXRVbml4TXMgPSBEYXRlLm5vdygpXG4gIH1cblxuICAvKipcbiAgICogUnVucyBjbGVhciBjb25uZWN0aW9uIGNoZWNrb3V0IG5hbWUuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIHdoZW4gY29tcGxldGUuXG4gICAqL1xuICBhc3luYyBjbGVhckNvbm5lY3Rpb25DaGVja291dE5hbWUoKSB7XG4gICAgdGhpcy5fY29ubmVjdGlvbkNoZWNrb3V0TmFtZSA9IHVuZGVmaW5lZFxuICAgIHRoaXMuX2Nvbm5lY3Rpb25DaGVja2VkT3V0QXRVbml4TXMgPSB1bmRlZmluZWRcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHJlY29ubmVjdC5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgd2hlbiBjb21wbGV0ZS5cbiAgICovXG4gIGFzeW5jIHJlY29ubmVjdCgpIHtcbiAgICB0aGlzLmNsZWFyU2NoZW1hQ2FjaGUoKVxuICAgIGF3YWl0IHRoaXMuY2xvc2UoKVxuICAgIGF3YWl0IHRoaXMuY29ubmVjdCgpXG4gIH1cblxuICAvKipcbiAgICogUnVucyBjcmVhdGUgZGF0YWJhc2Ugc3FsLlxuICAgKiBAYWJzdHJhY3RcbiAgICogQHBhcmFtIHtzdHJpbmd9IGRhdGFiYXNlTmFtZSAtIERhdGFiYXNlIG5hbWUuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBbYXJnc10gLSBPcHRpb25zIG9iamVjdC5cbiAgICogQHBhcmFtIHtib29sZWFufSBbYXJncy5pZk5vdEV4aXN0c10gLSBXaGV0aGVyIGlmIG5vdCBleGlzdHMuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbYXJncy5kYXRhYmFzZUNoYXJzZXRdIC0gRGF0YWJhc2UtZGVmYXVsdCBjaGFyYWN0ZXIgc2V0IChkcml2ZXItc3BlY2lmaWM7IG15c3FsL21hcmlhZGIpLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2FyZ3MuZGF0YWJhc2VDb2xsYXRpb25dIC0gRGF0YWJhc2UtZGVmYXVsdCBjb2xsYXRpb24gKGRyaXZlci1zcGVjaWZpYzsgbXlzcWwvbWFyaWFkYikuXG4gICAqIEByZXR1cm5zIHtzdHJpbmdbXX0gLSBTUUwgc3RhdGVtZW50cy5cbiAgICovXG4gIGNyZWF0ZURhdGFiYXNlU3FsKGRhdGFiYXNlTmFtZSwgYXJncykgeyB0aHJvdyBuZXcgRXJyb3IoXCInY3JlYXRlRGF0YWJhc2VTcWwnIG5vdCBpbXBsZW1lbnRlZFwiKSB9IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tdW51c2VkLXZhcnNcblxuICAvKipcbiAgICogUnVucyBkcm9wIGRhdGFiYXNlIHNxbC5cbiAgICogQGFic3RyYWN0XG4gICAqIEBwYXJhbSB7c3RyaW5nfSBkYXRhYmFzZU5hbWUgLSBEYXRhYmFzZSBuYW1lLlxuICAgKiBAcGFyYW0ge29iamVjdH0gW2FyZ3NdIC0gT3B0aW9ucyBvYmplY3QuXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gW2FyZ3MuaWZFeGlzdHNdIC0gV2hldGhlciBpZiBleGlzdHMuXG4gICAqIEByZXR1cm5zIHtzdHJpbmdbXX0gLSBTUUwgc3RhdGVtZW50cy5cbiAgICovXG4gIGRyb3BEYXRhYmFzZVNxbChkYXRhYmFzZU5hbWUsIGFyZ3MpIHsgdGhyb3cgbmV3IEVycm9yKFwiJ2Ryb3BEYXRhYmFzZVNxbCcgbm90IGltcGxlbWVudGVkXCIpIH0gLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby11bnVzZWQtdmFyc1xuXG4gIC8qKlxuICAgKiBSdW5zIGNyZWF0ZSBpbmRleCBzcWxzLlxuICAgKiBAYWJzdHJhY3RcbiAgICogQHBhcmFtIHtDcmVhdGVJbmRleFNxbEFyZ3N9IGluZGV4RGF0YSAtIEluZGV4IGRhdGEuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZ1tdPn0gLSBSZXNvbHZlcyB3aXRoIFNRTCBzdGF0ZW1lbnRzLlxuICAgKi9cbiAgYXN5bmMgY3JlYXRlSW5kZXhTUUxzKGluZGV4RGF0YSkgeyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVudXNlZC12YXJzXG4gICAgdGhyb3cgbmV3IEVycm9yKFwiJ2NyZWF0ZUluZGV4U1FMcycgbm90IGltcGxlbWVudGVkXCIpXG4gIH1cblxuICAvKipcbiAgICogUnVucyBjcmVhdGUgdGFibGUuXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vdGFibGUtZGF0YS9pbmRleC5qc1wiKS5kZWZhdWx0fSB0YWJsZURhdGEgLSBUYWJsZSBkYXRhLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBSZXNvbHZlcyB3aGVuIGNvbXBsZXRlLlxuICAgKi9cbiAgYXN5bmMgY3JlYXRlVGFibGUodGFibGVEYXRhKSB7XG4gICAgdGhpcy5fYXNzZXJ0Tm90UmVhZE9ubHkoKVxuICAgIGNvbnN0IHNxbHMgPSBhd2FpdCB0aGlzLmNyZWF0ZVRhYmxlU3FsKHRhYmxlRGF0YSlcblxuICAgIGZvciAoY29uc3Qgc3FsIG9mIHNxbHMpIHtcbiAgICAgIGF3YWl0IHRoaXMucXVlcnkoc3FsKVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGNyZWF0ZSB0YWJsZSBzcWwuXG4gICAqIEBhYnN0cmFjdFxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4uL3RhYmxlLWRhdGEvaW5kZXguanNcIikuZGVmYXVsdH0gdGFibGVEYXRhIC0gVGFibGUgZGF0YS5cbiAgICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nW10+fSAtIFJlc29sdmVzIHdpdGggU1FMIHN0YXRlbWVudHMuXG4gICAqL1xuICBhc3luYyBjcmVhdGVUYWJsZVNxbCh0YWJsZURhdGEpIHsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby11bnVzZWQtdmFyc1xuICAgIHRocm93IG5ldyBFcnJvcihcIidjcmVhdGVUYWJsZVNxbCcgbm90IGltcGxlbWVudGVkXCIpXG4gIH1cblxuICAvKipcbiAgICogUnVucyBkZWxldGUuXG4gICAqIEBwYXJhbSB7RGVsZXRlU3FsQXJnc1R5cGV9IGFyZ3MgLSBPcHRpb25zIG9iamVjdC5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgd2hlbiBjb21wbGV0ZS5cbiAgICovXG4gIGFzeW5jIGRlbGV0ZShhcmdzKSB7XG4gICAgdGhpcy5fYXNzZXJ0Tm90UmVhZE9ubHkoKVxuICAgIGNvbnN0IHNxbCA9IHRoaXMuZGVsZXRlU3FsKGFyZ3MpXG5cbiAgICBhd2FpdCB0aGlzLnF1ZXJ5KHNxbClcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGRlbGV0ZSBzcWwuXG4gICAqIEBhYnN0cmFjdFxuICAgKiBAcGFyYW0ge0RlbGV0ZVNxbEFyZ3NUeXBlfSBhcmdzIC0gT3B0aW9ucyBvYmplY3QuXG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IC0gU1FMIHN0cmluZy5cbiAgICovXG4gIGRlbGV0ZVNxbChhcmdzKSB7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tdW51c2VkLXZhcnNcbiAgICB0aHJvdyBuZXcgRXJyb3IoYCdkZWxldGVTcWwnIG5vdCBpbXBsZW1lbnRlZGApXG4gIH1cblxuICAvKipcbiAgICogUnVucyBkcm9wIHRhYmxlLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gdGFibGVOYW1lIC0gVGFibGUgbmFtZS5cbiAgICogQHBhcmFtIHtEcm9wVGFibGVTcWxBcmdzVHlwZX0gW2FyZ3NdIC0gT3B0aW9ucyBvYmplY3QuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIHdoZW4gY29tcGxldGUuXG4gICAqL1xuICBhc3luYyBkcm9wVGFibGUodGFibGVOYW1lLCBhcmdzKSB7XG4gICAgdGhpcy5fYXNzZXJ0Tm90UmVhZE9ubHkoKVxuICAgIGNvbnN0IHNxbHMgPSBhd2FpdCB0aGlzLmRyb3BUYWJsZVNRTHModGFibGVOYW1lLCBhcmdzKVxuXG4gICAgZm9yIChjb25zdCBzcWwgb2Ygc3Fscykge1xuICAgICAgYXdhaXQgdGhpcy5xdWVyeShzcWwpXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgZHJvcCB0YWJsZSBzcWxzLlxuICAgKiBAYWJzdHJhY3RcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRhYmxlTmFtZSAtIFRhYmxlIG5hbWUuXG4gICAqIEBwYXJhbSB7RHJvcFRhYmxlU3FsQXJnc1R5cGV9IFthcmdzXSAtIE9wdGlvbnMgb2JqZWN0LlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmdbXT59IC0gUmVzb2x2ZXMgd2l0aCBTUUwgc3RhdGVtZW50cy5cbiAgICovXG4gIGFzeW5jIGRyb3BUYWJsZVNRTHModGFibGVOYW1lLCBhcmdzKSB7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tdW51c2VkLXZhcnNcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJkcm9wVGFibGVTUUxzIG5vdCBpbXBsZW1lbnRlZFwiKVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgZXNjYXBlLlxuICAgKiBAYWJzdHJhY3RcbiAgICogQHBhcmFtIHs/fSB2YWx1ZSAtIFZhbHVlIHRvIHVzZS5cbiAgICogQHJldHVybnMgez99IC0gVGhlIGVzY2FwZS5cbiAgICovXG4gIGVzY2FwZSh2YWx1ZSkgeyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVudXNlZC12YXJzXG4gICAgdGhyb3cgbmV3IEVycm9yKFwiJ2VzY2FwZScgbm90IGltcGxlbWVudGVkXCIpXG4gIH1cblxuICAvKipcbiAgICogUnVucyBnZXQgYXJncy5cbiAgICogQHJldHVybnMge2ltcG9ydChcIi4uLy4uL2NvbmZpZ3VyYXRpb24tdHlwZXMuanNcIikuRGF0YWJhc2VDb25maWd1cmF0aW9uVHlwZX0gLSBUaGUgYXJncy5cbiAgICovXG4gIGdldEFyZ3MoKSB7XG4gICAgcmV0dXJuIHRoaXMuX2FyZ3NcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGdldCBjb25maWd1cmF0aW9uLlxuICAgKiBAcmV0dXJucyB7aW1wb3J0KFwiLi4vLi4vY29uZmlndXJhdGlvbi5qc1wiKS5kZWZhdWx0fSAtIFRoZSBjb25maWd1cmF0aW9uLlxuICAgKi9cbiAgZ2V0Q29uZmlndXJhdGlvbigpIHtcbiAgICBpZiAoIXRoaXMuY29uZmlndXJhdGlvbikgdGhyb3cgbmV3IEVycm9yKFwiTm8gY29uZmlndXJhdGlvbiBzZXRcIilcblxuICAgIHJldHVybiB0aGlzLmNvbmZpZ3VyYXRpb25cbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGdldCBpZCBzZXEuXG4gICAqIEByZXR1cm5zIHtudW1iZXIgfCB1bmRlZmluZWR9IC0gVGhlIGlkIHNlcS5cbiAgICovXG4gIGdldElkU2VxKCkge1xuICAgIHJldHVybiB0aGlzLmlkU2VxXG4gIH1cblxuICAvKipcbiAgICogQ2xlYXJzIGNhY2hlZCBzY2hlbWEgbWV0YWRhdGEgZm9yIHRoaXMgZHJpdmVyIGluc3RhbmNlLlxuICAgKiBAcmV0dXJucyB7dm9pZH0gLSBObyByZXR1cm4gdmFsdWUuXG4gICAqL1xuICBjbGVhclNjaGVtYUNhY2hlKCkge1xuICAgIGlmICh0aGlzLl9zY2hlbWFDYWNoZUludmFsaWRhdG9yKSB7XG4gICAgICB0aGlzLl9zY2hlbWFDYWNoZUludmFsaWRhdG9yKClcbiAgICAgIHJldHVyblxuICAgIH1cblxuICAgIHRoaXMuX2NsZWFyTG9jYWxTY2hlbWFDYWNoZSgpXG4gIH1cblxuICAvKipcbiAgICogQ2xlYXJzIG9ubHkgdGhlIG1ldGFkYXRhIGNhY2hlZCBvbiB0aGlzIGRyaXZlciBpbnN0YW5jZS5cbiAgICogQHJldHVybnMge3ZvaWR9IC0gTm8gcmV0dXJuIHZhbHVlLlxuICAgKi9cbiAgX2NsZWFyTG9jYWxTY2hlbWFDYWNoZSgpIHtcbiAgICB0aGlzLl9zY2hlbWFDYWNoZS5jbGVhcigpXG4gIH1cblxuICAvKipcbiAgICogUnVucyBzZXQgc2NoZW1hIGNhY2hlIGludmFsaWRhdG9yLlxuICAgKiBAcGFyYW0geygpID0+IHZvaWR9IGludmFsaWRhdG9yIC0gQ2FsbGJhY2sgdXNlZCB0byBjbGVhciBzY2hlbWEgY2FjaGVzIHRoYXQgc2hhcmUgdGhpcyBkcml2ZXIgcG9vbC5cbiAgICogQHJldHVybnMge3ZvaWR9IC0gTm8gcmV0dXJuIHZhbHVlLlxuICAgKi9cbiAgc2V0U2NoZW1hQ2FjaGVJbnZhbGlkYXRvcihpbnZhbGlkYXRvcikge1xuICAgIHRoaXMuX3NjaGVtYUNhY2hlSW52YWxpZGF0b3IgPSBpbnZhbGlkYXRvclxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgc2NoZW1hIGNhY2hlIGVuYWJsZWQuXG4gICAqIEByZXR1cm5zIHtib29sZWFufSAtIFdoZXRoZXIgc2NoZW1hIG1ldGFkYXRhIGNhY2hpbmcgaXMgZW5hYmxlZC5cbiAgICovXG4gIF9zY2hlbWFDYWNoZUVuYWJsZWQoKSB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0QXJncygpLnNjaGVtYUNhY2hlICE9PSBmYWxzZVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgY2FjaGVkIHNjaGVtYSBtZXRhZGF0YS5cbiAgICogQHRlbXBsYXRlIFRcbiAgICogQHBhcmFtIHtzdHJpbmd9IGNhY2hlS2V5IC0gU2NoZW1hIGNhY2hlIGtleS5cbiAgICogQHBhcmFtIHsoKSA9PiBQcm9taXNlPFQ+fSBjYWxsYmFjayAtIENhY2hlIG1pc3MgY2FsbGJhY2suXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPFQ+fSAtIFJlc29sdmVzIHdpdGggdGhlIGNhY2hlZCBtZXRhZGF0YS5cbiAgICovXG4gIGFzeW5jIF9jYWNoZWRTY2hlbWFNZXRhZGF0YShjYWNoZUtleSwgY2FsbGJhY2spIHtcbiAgICBpZiAoIXRoaXMuX3NjaGVtYUNhY2hlRW5hYmxlZCgpKSByZXR1cm4gYXdhaXQgY2FsbGJhY2soKVxuXG4gICAgY29uc3QgZXhpc3RpbmdQcm9taXNlID0gdGhpcy5fc2NoZW1hQ2FjaGUuZ2V0KGNhY2hlS2V5KVxuXG4gICAgaWYgKGV4aXN0aW5nUHJvbWlzZSkge1xuICAgICAgcmV0dXJuIC8qKiBOYXJyb3dzIHRoZSBydW50aW1lIHZhbHVlIHRvIHRoZSBkb2N1bWVudGVkIHR5cGUuIEB0eXBlIHtUfSAqLyAodGhpcy5fc2NoZW1hQ2FjaGVSZXR1cm5WYWx1ZShhd2FpdCBleGlzdGluZ1Byb21pc2UpKVxuICAgIH1cblxuICAgIGNvbnN0IHByb21pc2UgPSAoYXN5bmMgKCkgPT4gYXdhaXQgY2FsbGJhY2soKSkoKVxuXG4gICAgdGhpcy5fc2NoZW1hQ2FjaGUuc2V0KGNhY2hlS2V5LCBwcm9taXNlKVxuXG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiAvKiogTmFycm93cyB0aGUgcnVudGltZSB2YWx1ZSB0byB0aGUgZG9jdW1lbnRlZCB0eXBlLiBAdHlwZSB7VH0gKi8gKHRoaXMuX3NjaGVtYUNhY2hlUmV0dXJuVmFsdWUoYXdhaXQgcHJvbWlzZSkpXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGlmICh0aGlzLl9zY2hlbWFDYWNoZS5nZXQoY2FjaGVLZXkpID09PSBwcm9taXNlKSB7XG4gICAgICAgIHRoaXMuX3NjaGVtYUNhY2hlLmRlbGV0ZShjYWNoZUtleSlcbiAgICAgIH1cblxuICAgICAgdGhyb3cgZXJyb3JcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUnVucyBjYWNoZWQgdGFibGUgc2NoZW1hIG1ldGFkYXRhLlxuICAgKiBAdGVtcGxhdGUgVFxuICAgKiBAcGFyYW0ge3N0cmluZ30gdGFibGVOYW1lIC0gVGFibGUgbmFtZS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IG1ldGFkYXRhTmFtZSAtIE1ldGFkYXRhIG5hbWUuXG4gICAqIEBwYXJhbSB7KCkgPT4gUHJvbWlzZTxUPn0gY2FsbGJhY2sgLSBDYWNoZSBtaXNzIGNhbGxiYWNrLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxUPn0gLSBSZXNvbHZlcyB3aXRoIHRoZSBjYWNoZWQgdGFibGUgbWV0YWRhdGEuXG4gICAqL1xuICBhc3luYyBfY2FjaGVkVGFibGVTY2hlbWFNZXRhZGF0YSh0YWJsZU5hbWUsIG1ldGFkYXRhTmFtZSwgY2FsbGJhY2spIHtcbiAgICByZXR1cm4gYXdhaXQgdGhpcy5fY2FjaGVkU2NoZW1hTWV0YWRhdGEoYHRhYmxlOiR7dGFibGVOYW1lfToke21ldGFkYXRhTmFtZX1gLCBjYWxsYmFjaylcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHNjaGVtYSBjYWNoZSByZXR1cm4gdmFsdWUuXG4gICAqIEBwYXJhbSB7P30gdmFsdWUgLSBDYWNoZWQgdmFsdWUuXG4gICAqIEByZXR1cm5zIHs/fSAtIFZhbHVlIHJldHVybmVkIHRvIGNhbGxlcnMuXG4gICAqL1xuICBfc2NoZW1hQ2FjaGVSZXR1cm5WYWx1ZSh2YWx1ZSkge1xuICAgIGlmIChBcnJheS5pc0FycmF5KHZhbHVlKSkgcmV0dXJuIHZhbHVlLnNsaWNlKClcblxuICAgIHJldHVybiB2YWx1ZVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgZ2V0IHRhYmxlcy5cbiAgICogQGFic3RyYWN0XG4gICAqIEByZXR1cm5zIHtQcm9taXNlPEFycmF5PGltcG9ydChcIi4vYmFzZS10YWJsZS5qc1wiKS5kZWZhdWx0Pj59IC0gUmVzb2x2ZXMgd2l0aCB0aGUgdGFibGVzLlxuICAgKi9cbiAgZ2V0VGFibGVzKCkge1xuICAgIHRocm93IG5ldyBFcnJvcihgJHt0aGlzLmNvbnN0cnVjdG9yLm5hbWV9I2dldFRhYmxlcyBub3QgaW1wbGVtZW50ZWRgKVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgc3RydWN0dXJlIHNxbC5cbiAgICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nIHwgbnVsbD59IC0gUmVzb2x2ZXMgd2l0aCBTUUwgc3RyaW5nLlxuICAgKi9cbiAgYXN5bmMgc3RydWN0dXJlU3FsKCkge1xuICAgIHJldHVybiBudWxsXG4gIH1cblxuICAvKipcbiAgICogUnVucyBnZXQgdGFibGUgYnkgbmFtZS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgLSBOYW1lLlxuICAgKiBAcGFyYW0ge29iamVjdH0gW2FyZ3NdIC0gT3B0aW9ucyBvYmplY3QuXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gYXJncy50aHJvd0Vycm9yIC0gV2hldGhlciB0aHJvdyBlcnJvci5cbiAgICogQHJldHVybnMge1Byb21pc2U8aW1wb3J0KFwiLi9iYXNlLXRhYmxlLmpzXCIpLmRlZmF1bHQgfCB1bmRlZmluZWQ+fSAtIFJlc29sdmVzIHdpdGggdGhlIHRhYmxlIGJ5IG5hbWUuXG4gICAqL1xuICBhc3luYyBnZXRUYWJsZUJ5TmFtZShuYW1lLCBhcmdzKSB7XG4gICAgY29uc3QgdGFibGVzID0gYXdhaXQgdGhpcy5nZXRUYWJsZXMoKVxuICAgIGNvbnN0IHRhYmxlTmFtZXMgPSBbXVxuICAgIGxldCB0YWJsZVxuXG4gICAgZm9yIChjb25zdCBjYW5kaWRhdGUgb2YgdGFibGVzKSB7XG4gICAgICBjb25zdCBjYW5kaWRhdGVOYW1lID0gY2FuZGlkYXRlLmdldE5hbWUoKVxuXG4gICAgICBpZiAoY2FuZGlkYXRlTmFtZSA9PSBuYW1lKSB7XG4gICAgICAgIHRhYmxlID0gY2FuZGlkYXRlXG4gICAgICAgIGJyZWFrXG4gICAgICB9XG5cbiAgICAgIHRhYmxlTmFtZXMucHVzaChjYW5kaWRhdGVOYW1lKVxuICAgIH1cblxuICAgIGlmICghdGFibGUgJiYgYXJncz8udGhyb3dFcnJvciAhPT0gZmFsc2UpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcih0aGlzLl9taXNzaW5nVGFibGVFcnJvck1lc3NhZ2UobmFtZSwgdGFibGVOYW1lcykpXG4gICAgfVxuXG4gICAgcmV0dXJuIHRhYmxlXG4gIH1cblxuICAvKipcbiAgICogUnVucyBtaXNzaW5nIHRhYmxlIGVycm9yIG1lc3NhZ2UuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIC0gVGFibGUgbmFtZS5cbiAgICogQHBhcmFtIHtzdHJpbmdbXX0gdGFibGVOYW1lcyAtIEF2YWlsYWJsZSB0YWJsZSBuYW1lcy5cbiAgICogQHJldHVybnMge3N0cmluZ30gLSBFcnJvciBtZXNzYWdlLlxuICAgKi9cbiAgX21pc3NpbmdUYWJsZUVycm9yTWVzc2FnZShuYW1lLCB0YWJsZU5hbWVzKSB7XG4gICAgY29uc3QgZW52aXJvbm1lbnQgPSB0aGlzLmdldENvbmZpZ3VyYXRpb24oKS5nZXRFbnZpcm9ubWVudCgpXG4gICAgY29uc3QgYXJncyA9IHRoaXMuZ2V0QXJncygpXG4gICAgY29uc3QgZGF0YWJhc2VOYW1lID0gYXJncz8uZGF0YWJhc2UgfHwgYXJncz8ubmFtZSB8fCBhcmdzPy51c2VEYXRhYmFzZSB8fCBcInVua25vd25cIlxuXG4gICAgcmV0dXJuIGBDb3VsZG4ndCBmaW5kIGEgdGFibGUgYnkgdGhhdCBuYW1lIFwiJHtuYW1lfVwiIGluOiAke3RhYmxlTmFtZXMuam9pbihcIiwgXCIpfSAoZW52aXJvbm1lbnQ6ICR7ZW52aXJvbm1lbnR9LCBkYXRhYmFzZTogJHtkYXRhYmFzZU5hbWV9KWBcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGdldCB0YWJsZSBieSBuYW1lIG9yIGZhaWwuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIC0gTmFtZS5cbiAgICogQHJldHVybnMge1Byb21pc2U8aW1wb3J0KFwiLi9iYXNlLXRhYmxlLmpzXCIpLmRlZmF1bHQ+fSAtIFJlc29sdmVzIHdpdGggdGhlIHRhYmxlIGJ5IG5hbWUgb3IgZmFpbC5cbiAgICovXG4gIGFzeW5jIGdldFRhYmxlQnlOYW1lT3JGYWlsKG5hbWUpIHtcbiAgICByZXR1cm4gLyoqIE5hcnJvd3MgdGhlIHJ1bnRpbWUgdmFsdWUgdG8gdGhlIGRvY3VtZW50ZWQgdHlwZS4gQHR5cGUge2ltcG9ydChcIi4vYmFzZS10YWJsZS5qc1wiKS5kZWZhdWx0fSAqLyAoYXdhaXQgdGhpcy5nZXRUYWJsZUJ5TmFtZShuYW1lLCB7dGhyb3dFcnJvcjogdHJ1ZX0pKVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgZ2V0IHR5cGUuXG4gICAqIEBhYnN0cmFjdFxuICAgKiBAcmV0dXJucyB7c3RyaW5nfSAtIFRoZSB0eXBlLlxuICAgKi9cbiAgZ2V0VHlwZSgpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCIndHlwZScgbm90IGltcGxlbWVudGVkXCIpXG4gIH1cblxuICAvKipcbiAgICogUnVucyBpbnNlcnQuXG4gICAqIEBwYXJhbSB7SW5zZXJ0U3FsQXJnc1R5cGV9IGFyZ3MgLSBPcHRpb25zIG9iamVjdC5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgd2hlbiBjb21wbGV0ZS5cbiAgICovXG4gIGFzeW5jIGluc2VydChhcmdzKSB7XG4gICAgdGhpcy5fYXNzZXJ0Tm90UmVhZE9ubHkoKVxuICAgIGNvbnN0IHNxbCA9IHRoaXMuaW5zZXJ0U3FsKGFyZ3MpXG5cbiAgICBhd2FpdCB0aGlzLnF1ZXJ5KHNxbClcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGluc2VydCBtdWx0aXBsZS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHRhYmxlTmFtZSAtIFRhYmxlIG5hbWUuXG4gICAqIEBwYXJhbSB7QXJyYXk8c3RyaW5nPn0gY29sdW1ucyAtIENvbHVtbiBuYW1lcy5cbiAgICogQHBhcmFtIHtBcnJheTxBcnJheTw/Pj59IHJvd3MgLSBSb3dzIHRvIGluc2VydC5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgd2hlbiBjb21wbGV0ZS5cbiAgICovXG4gIGFzeW5jIGluc2VydE11bHRpcGxlKHRhYmxlTmFtZSwgY29sdW1ucywgcm93cykge1xuICAgIHRoaXMuX2Fzc2VydE5vdFJlYWRPbmx5KClcblxuICAgIGNvbnN0IHNxbCA9IHRoaXMuaW5zZXJ0U3FsKHtjb2x1bW5zLCB0YWJsZU5hbWUsIHJvd3N9KVxuXG4gICAgYXdhaXQgdGhpcy5xdWVyeShzcWwpXG4gIH1cblxuICAvKipcbiAgICogUnVucyBpbnNlcnQgc3FsLlxuICAgKiBAYWJzdHJhY3RcbiAgICogQHBhcmFtIHtJbnNlcnRTcWxBcmdzVHlwZX0gYXJncyAtIE9wdGlvbnMgb2JqZWN0LlxuICAgKiBAcmV0dXJucyB7c3RyaW5nfSAtIFNRTCBzdHJpbmcuXG4gICAqL1xuICBpbnNlcnRTcWwoYXJncykgeyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVudXNlZC12YXJzXG4gICAgdGhyb3cgbmV3IEVycm9yKFwiJ2luc2VydFNxbCcgbm90IGltcGxlbWVudGVkXCIpXG4gIH1cblxuICAvKipcbiAgICogUnVucyB1cHNlcnQuXG4gICAqIEBwYXJhbSB7VXBzZXJ0U3FsQXJnc1R5cGV9IGFyZ3MgLSBPcHRpb25zIG9iamVjdC5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgd2hlbiBjb21wbGV0ZS5cbiAgICovXG4gIGFzeW5jIHVwc2VydChhcmdzKSB7XG4gICAgdGhpcy5fYXNzZXJ0Tm90UmVhZE9ubHkoKVxuICAgIGNvbnN0IHNxbCA9IHRoaXMudXBzZXJ0U3FsKGFyZ3MpXG5cbiAgICBhd2FpdCB0aGlzLnF1ZXJ5KHNxbClcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGxhc3QgaW5zZXJ0IGlkLlxuICAgKiBAYWJzdHJhY3RcbiAgICogQHJldHVybnMge1Byb21pc2U8bnVtYmVyPn0gLSBSZXNvbHZlcyB3aXRoIHRoZSBsYXN0IGluc2VydCBpZC5cbiAgICovXG4gIGxhc3RJbnNlcnRJRCgpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYCR7dGhpcy5jb25zdHJ1Y3Rvci5uYW1lfSNsYXN0SW5zZXJ0SUQgbm90IGltcGxlbWVudGVkYClcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGNvbnZlcnQgdmFsdWUuXG4gICAqIEBwYXJhbSB7P30gdmFsdWUgLSBWYWx1ZSB0byB1c2UuXG4gICAqIEByZXR1cm5zIHs/fSAtIFRoZSBjb252ZXJ0IHZhbHVlLlxuICAgKi9cbiAgX2NvbnZlcnRWYWx1ZSh2YWx1ZSkge1xuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09IFwiYm9vbGVhblwiKSB7XG4gICAgICByZXR1cm4gdmFsdWUgPyAxIDogMFxuICAgIH1cblxuICAgIGlmICh2YWx1ZSBpbnN0YW5jZW9mIERhdGUpIHtcbiAgICAgIHJldHVybiBzdHJmdGltZShcIiVGICVULiVMXCIsIHZhbHVlKVxuICAgIH1cblxuICAgIC8vIEpTT04tZW5jb2RlIHBsYWluIG9iamVjdHMvYXJyYXlzIHNvIHRoZXkgbGFuZCBpbiBKU09OL3RleHQgY29sdW1ucyBhcyB2YWxpZFxuICAgIC8vIEpTT04uIFdpdGhvdXQgdGhpcywgZHJpdmVycyBsaWtlIG15c3FsJ3MgZXNjYXBlKCkgdHVybiBhbiBvYmplY3QgaW50b1xuICAgIC8vIGBrZXlgID0gdmFsdWUgYXNzaWdubWVudCBwYWlycyAoaXRzIGBTRVQgP2AgZm9ybSksIHByb2R1Y2luZyBpbnZhbGlkIFNRTCBpblxuICAgIC8vIGEgdmFsdWUgcG9zaXRpb24uIE9ubHkgUExBSU4gb2JqZWN0cyBhbmQgYXJyYXlzIGFyZSBlbmNvZGVkIOKAlCBjbGFzc1xuICAgIC8vIGluc3RhbmNlcyAoZS5nLiBtb2RlbCByZWNvcmRzLCB3aGljaCBhcmUgY2lyY3VsYXIgdmlhIF9jaGFuZ2VzKSBhbmQgQnVmZmVyc1xuICAgIC8vIHBhc3MgdGhyb3VnaCB1bnRvdWNoZWQsIHNpbmNlIEpTT04uc3RyaW5naWZ5IG9uIGEgcmVjb3JkIHRocm93cyBvbiBpdHNcbiAgICAvLyBjaXJjdWxhciBzdHJ1Y3R1cmUgYW5kIGEgcmVjb3JkIGlzIG5ldmVyIGEgdmFsaWQgY29sdW1uIHZhbHVlIHRvIHNlcmlhbGl6ZS5cbiAgICBpZiAodGhpcy5faXNKc29uRW5jb2RhYmxlVmFsdWUodmFsdWUpKSB7XG4gICAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkodmFsdWUpXG4gICAgfVxuXG4gICAgcmV0dXJuIHZhbHVlXG4gIH1cblxuICAvKipcbiAgICogV2hldGhlciBhIHZhbHVlIGlzIGEgcGxhaW4gb2JqZWN0IG9yIGFycmF5IHRoYXQgc2hvdWxkIGJlIEpTT04tZW5jb2RlZCBmb3IgYVxuICAgKiBKU09OL3RleHQgY29sdW1uLiBFeGNsdWRlcyBCdWZmZXJzIGFuZCBjbGFzcyBpbnN0YW5jZXMgKGUuZy4gbW9kZWwgcmVjb3JkcykuXG4gICAqIEBwYXJhbSB7P30gdmFsdWUgLSBWYWx1ZSB0byB0ZXN0LlxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBXaGV0aGVyIHRvIEpTT04tZW5jb2RlIHRoZSB2YWx1ZS5cbiAgICovXG4gIF9pc0pzb25FbmNvZGFibGVWYWx1ZSh2YWx1ZSkge1xuICAgIGlmICh2YWx1ZSA9PT0gbnVsbCB8fCB0eXBlb2YgdmFsdWUgIT09IFwib2JqZWN0XCIpIHJldHVybiBmYWxzZVxuICAgIGlmICh0eXBlb2YgQnVmZmVyICE9PSBcInVuZGVmaW5lZFwiICYmIEJ1ZmZlci5pc0J1ZmZlcih2YWx1ZSkpIHJldHVybiBmYWxzZVxuICAgIGlmIChBcnJheS5pc0FycmF5KHZhbHVlKSkgcmV0dXJuIHRydWVcblxuICAgIGNvbnN0IHByb3RvdHlwZSA9IE9iamVjdC5nZXRQcm90b3R5cGVPZih2YWx1ZSlcblxuICAgIHJldHVybiBwcm90b3R5cGUgPT09IE9iamVjdC5wcm90b3R5cGUgfHwgcHJvdG90eXBlID09PSBudWxsXG4gIH1cblxuICAvKipcbiAgICogUnVucyBvcHRpb25zLlxuICAgKiBAYWJzdHJhY3RcbiAgICogQHJldHVybnMge2ltcG9ydChcIi4uL3F1ZXJ5LXBhcnNlci9vcHRpb25zLmpzXCIpLmRlZmF1bHR9IC0gVGhlIG9wdGlvbnMgb3B0aW9ucy5cbiAgICovXG4gIG9wdGlvbnMoKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFwiJ29wdGlvbnMnIG5vdCBpbXBsZW1lbnRlZC5cIilcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHF1b3RlLlxuICAgKiBAcGFyYW0gez99IHZhbHVlIC0gVmFsdWUgdG8gdXNlLlxuICAgKiBAcmV0dXJucyB7bnVtYmVyIHwgc3RyaW5nfSAtIFRoZSBxdW90ZS5cbiAgICovXG4gIHF1b3RlKHZhbHVlKSB7XG4gICAgaWYgKHR5cGVvZiB2YWx1ZSA9PSBcIm51bWJlclwiKSByZXR1cm4gdmFsdWVcblxuICAgIGNvbnN0IGVzY2FwZWRWYWx1ZSA9IHRoaXMuZXNjYXBlKHZhbHVlKVxuICAgIGNvbnN0IHJlc3VsdCA9IGBcIiR7ZXNjYXBlZFZhbHVlfVwiYFxuXG4gICAgcmV0dXJuIHJlc3VsdFxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgcXVvdGUgY29sdW1uLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gY29sdW1uTmFtZSAtIENvbHVtbiBuYW1lLlxuICAgKiBAcmV0dXJucyB7c3RyaW5nfSAtIFRoZSBxdW90ZSBjb2x1bW4uXG4gICAqL1xuICBxdW90ZUNvbHVtbihjb2x1bW5OYW1lKSB7XG4gICAgcmV0dXJuIHRoaXMub3B0aW9ucygpLnF1b3RlQ29sdW1uTmFtZShjb2x1bW5OYW1lKVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgcXVvdGUgaW5kZXguXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBjb2x1bW5OYW1lIC0gQ29sdW1uIG5hbWUuXG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIHF1b3RlIGluZGV4LlxuICAgKi9cbiAgcXVvdGVJbmRleChjb2x1bW5OYW1lKSB7XG4gICAgcmV0dXJuIHRoaXMub3B0aW9ucygpLnF1b3RlSW5kZXhOYW1lKGNvbHVtbk5hbWUpXG4gIH1cblxuICAvKipcbiAgICogUnVucyBxdW90ZSB0YWJsZS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHRhYmxlTmFtZSAtIFRhYmxlIG5hbWUuXG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIHF1b3RlIHRhYmxlLlxuICAgKi9cbiAgcXVvdGVUYWJsZSh0YWJsZU5hbWUpIHtcbiAgICByZXR1cm4gdGhpcy5vcHRpb25zKCkucXVvdGVUYWJsZU5hbWUodGFibGVOYW1lKVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgbmV3IHF1ZXJ5LlxuICAgKiBAcmV0dXJucyB7UXVlcnl9IC0gVGhlIG5ldyBxdWVyeS5cbiAgICovXG4gIG5ld1F1ZXJ5KCkge1xuICAgIGNvbnN0IGhhbmRsZXIgPSBuZXcgSGFuZGxlcigpXG5cbiAgICByZXR1cm4gbmV3IFF1ZXJ5KHtcbiAgICAgIGRyaXZlcjogdGhpcyxcbiAgICAgIGhhbmRsZXJcbiAgICB9KVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgc2VsZWN0LlxuICAgKiBAcGFyYW0ge3N0cmluZ30gdGFibGVOYW1lIC0gVGFibGUgbmFtZS5cbiAgICogQHJldHVybnMge1Byb21pc2U8UXVlcnlSZXN1bHRUeXBlPn0gLSBSZXNvbHZlcyB3aXRoIHRoZSBzZWxlY3QuXG4gICAqL1xuICBhc3luYyBzZWxlY3QodGFibGVOYW1lKSB7XG4gICAgY29uc3QgcXVlcnkgPSB0aGlzLm5ld1F1ZXJ5KClcblxuICAgIGNvbnN0IHNxbCA9IHF1ZXJ5XG4gICAgICAuZnJvbSh0YWJsZU5hbWUpXG4gICAgICAudG9TcWwoKVxuXG4gICAgcmV0dXJuIGF3YWl0IHRoaXMucXVlcnkoc3FsKVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgc2V0IGlkIHNlcS5cbiAgICogQHBhcmFtIHtudW1iZXIgfCB1bmRlZmluZWR9IG5ld0lkU2VxIC0gTmV3IGlkIHNlcS5cbiAgICogQHJldHVybnMge3ZvaWR9IC0gTm8gcmV0dXJuIHZhbHVlLlxuICAgKi9cbiAgc2V0SWRTZXEobmV3SWRTZXEpIHtcbiAgICB0aGlzLmlkU2VxID0gbmV3SWRTZXFcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHNob3VsZCBzZXQgYXV0byBpbmNyZW1lbnQgd2hlbiBwcmltYXJ5IGtleS5cbiAgICogQGFic3RyYWN0XG4gICAqIEByZXR1cm5zIHtib29sZWFufSAtIFdoZXRoZXIgc2V0IGF1dG8gaW5jcmVtZW50IHdoZW4gcHJpbWFyeSBrZXkuXG4gICAqL1xuICBzaG91bGRTZXRBdXRvSW5jcmVtZW50V2hlblByaW1hcnlLZXkoKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGAnc2hvdWxkU2V0QXV0b0luY3JlbWVudFdoZW5QcmltYXJ5S2V5JyBub3QgaW1wbGVtZW50ZWRgKVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgc3VwcG9ydHMgZGVmYXVsdCBwcmltYXJ5IGtleSB1dWlkLlxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBXaGV0aGVyIHN1cHBvcnRzIGRlZmF1bHQgcHJpbWFyeSBrZXkgdXVpZC5cbiAgICovXG4gIHN1cHBvcnRzRGVmYXVsdFByaW1hcnlLZXlVVUlEKCkgeyByZXR1cm4gZmFsc2UgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHN1cHBvcnRzIGluc2VydCBpbnRvIHJldHVybmluZy5cbiAgICogQGFic3RyYWN0XG4gICAqIEByZXR1cm5zIHtib29sZWFufSAtIFdoZXRoZXIgc3VwcG9ydHMgaW5zZXJ0IGludG8gcmV0dXJuaW5nLlxuICAgKi9cbiAgc3VwcG9ydHNJbnNlcnRJbnRvUmV0dXJuaW5nKCkgeyByZXR1cm4gZmFsc2UgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHRhYmxlIGV4aXN0cy5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHRhYmxlTmFtZSAtIFRhYmxlIG5hbWUuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSAtIFJlc29sdmVzIHdpdGggV2hldGhlciB0YWJsZSBleGlzdHMuXG4gICAqL1xuICBhc3luYyB0YWJsZUV4aXN0cyh0YWJsZU5hbWUpIHtcbiAgICBjb25zdCB0YWJsZXMgPSBhd2FpdCB0aGlzLmdldFRhYmxlcygpXG4gICAgY29uc3QgdGFibGUgPSB0YWJsZXMuZmluZCgodGFibGUpID0+IHRhYmxlLmdldE5hbWUoKSA9PSB0YWJsZU5hbWUpXG5cbiAgICBpZiAodGFibGUpIHJldHVybiB0cnVlXG5cbiAgICByZXR1cm4gZmFsc2VcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHRyYW5zYWN0aW9uLlxuICAgKiBAcGFyYW0geygpID0+IFByb21pc2U8dm9pZD59IGNhbGxiYWNrIC0gQ2FsbGJhY2sgZnVuY3Rpb24uXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPD8+fSAtIFJlc29sdmVzIHdpdGggdGhlIHRyYW5zYWN0aW9uLlxuICAgKi9cbiAgYXN5bmMgdHJhbnNhY3Rpb24oY2FsbGJhY2spIHtcbiAgICBjb25zdCBzYXZlUG9pbnROYW1lID0gdGhpcy5nZW5lcmF0ZVNhdmVQb2ludE5hbWUoKVxuICAgIC8qKlxuICAgICAqIENhbGxiYWNrIGZyYW1lLlxuICAgICAgQHR5cGUge0FycmF5PCgpID0+IHZvaWQgfCBQcm9taXNlPHZvaWQ+Pn0gKi9cbiAgICBjb25zdCBjYWxsYmFja0ZyYW1lID0gW11cbiAgICBsZXQgdHJhbnNhY3Rpb25TdGFydGVkID0gZmFsc2VcbiAgICBsZXQgc2F2ZVBvaW50U3RhcnRlZCA9IGZhbHNlXG5cbiAgICB0aGlzLl9hZnRlckNvbW1pdENhbGxiYWNrRnJhbWVzLnB1c2goY2FsbGJhY2tGcmFtZSlcblxuICAgIGlmICh0aGlzLl90cmFuc2FjdGlvbnNDb3VudCA9PSAwKSB7XG4gICAgICB0aGlzLmxvZ2dlci5kZWJ1ZyhcIlN0YXJ0IHRyYW5zYWN0aW9uXCIpXG4gICAgICBhd2FpdCB0aGlzLnN0YXJ0VHJhbnNhY3Rpb24oKVxuICAgICAgdHJhbnNhY3Rpb25TdGFydGVkID0gdHJ1ZVxuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmxvZ2dlci5kZWJ1ZyhcIlN0YXJ0IHNhdmVwb2ludFwiLCBzYXZlUG9pbnROYW1lKVxuICAgICAgYXdhaXQgdGhpcy5zdGFydFNhdmVQb2ludChzYXZlUG9pbnROYW1lKVxuICAgICAgc2F2ZVBvaW50U3RhcnRlZCA9IHRydWVcbiAgICB9XG5cbiAgICBsZXQgcmVzdWx0XG5cbiAgICB0cnkge1xuICAgICAgcmVzdWx0ID0gYXdhaXQgY2FsbGJhY2soKVxuXG4gICAgICBpZiAoc2F2ZVBvaW50U3RhcnRlZCkge1xuICAgICAgICB0aGlzLmxvZ2dlci5kZWJ1ZyhcIlJlbGVhc2Ugc2F2ZXBvaW50XCIsIHNhdmVQb2ludE5hbWUpXG4gICAgICAgIGF3YWl0IHRoaXMucmVsZWFzZVNhdmVQb2ludChzYXZlUG9pbnROYW1lKVxuICAgICAgfVxuXG4gICAgICBpZiAodHJhbnNhY3Rpb25TdGFydGVkKSB7XG4gICAgICAgIHRoaXMubG9nZ2VyLmRlYnVnKFwiQ29tbWl0IHRyYW5zYWN0aW9uXCIpXG4gICAgICAgIGF3YWl0IHRoaXMuY29tbWl0VHJhbnNhY3Rpb24oKVxuICAgICAgfVxuXG4gICAgICBhd2FpdCB0aGlzLl9jb21taXRBZnRlckNvbW1pdENhbGxiYWNrRnJhbWUoKVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgICB0aGlzLmxvZ2dlci5kZWJ1ZyhcIlRyYW5zYWN0aW9uIGVycm9yXCIsIGVycm9yLm1lc3NhZ2UpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLmxvZ2dlci5kZWJ1ZyhcIlRyYW5zYWN0aW9uIGVycm9yXCIsIGVycm9yKVxuICAgICAgfVxuXG4gICAgICBsZXQgdHJhbnNhY3Rpb25Sb2xsZWRCYWNrID0gZmFsc2VcblxuICAgICAgaWYgKHNhdmVQb2ludFN0YXJ0ZWQpIHtcbiAgICAgICAgdGhpcy5sb2dnZXIuZGVidWcoXCJSb2xsYmFjayBzYXZlcG9pbnRcIiwgc2F2ZVBvaW50TmFtZSlcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBhd2FpdCB0aGlzLnJvbGxiYWNrU2F2ZVBvaW50KHNhdmVQb2ludE5hbWUpXG4gICAgICAgIH0gY2F0Y2ggKHNhdmVQb2ludEVycm9yKSB7XG4gICAgICAgICAgY29uc3QgbWVzc2FnZSA9IHNhdmVQb2ludEVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBzYXZlUG9pbnRFcnJvci5tZXNzYWdlIDogYCR7c2F2ZVBvaW50RXJyb3J9YFxuXG4gICAgICAgICAgLy8gTXlTUUwgc29tZXRpbWVzIGRyb3BzIHNhdmVwb2ludHMgdW5leHBlY3RlZGx5OyBmYWxsIGJhY2sgdG8gcm9sbGluZyBiYWNrIHRoZSBmdWxsIHRyYW5zYWN0aW9uXG4gICAgICAgICAgaWYgKG1lc3NhZ2UuaW5jbHVkZXMoXCJTQVZFUE9JTlRcIikgfHwgbWVzc2FnZS5pbmNsdWRlcyhcIkVSX1NQX0RPRVNfTk9UX0VYSVNUXCIpKSB7XG4gICAgICAgICAgICB0aGlzLmxvZ2dlci5kZWJ1ZyhcIlNhdmVwb2ludCByb2xsYmFjayBmYWlsZWQ7IHJvbGxpbmcgYmFjayBlbnRpcmUgdHJhbnNhY3Rpb24gaW5zdGVhZFwiKVxuICAgICAgICAgICAgYXdhaXQgdGhpcy5yb2xsYmFja1RyYW5zYWN0aW9uKClcbiAgICAgICAgICAgIHRyYW5zYWN0aW9uUm9sbGVkQmFjayA9IHRydWVcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgc2F2ZVBvaW50RXJyb3JcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKHRyYW5zYWN0aW9uU3RhcnRlZCAmJiAhdHJhbnNhY3Rpb25Sb2xsZWRCYWNrKSB7XG4gICAgICAgIHRoaXMubG9nZ2VyLmRlYnVnKFwiUm9sbGJhY2sgdHJhbnNhY3Rpb25cIilcbiAgICAgICAgYXdhaXQgdGhpcy5yb2xsYmFja1RyYW5zYWN0aW9uKClcbiAgICAgIH1cblxuICAgICAgdGhpcy5fYWZ0ZXJDb21taXRDYWxsYmFja0ZyYW1lcy5wb3AoKVxuXG4gICAgICB0aHJvdyBlcnJvclxuICAgIH1cblxuICAgIHJldHVybiByZXN1bHRcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGEgY2FsbGJhY2sgYWZ0ZXIgdGhlIHN1cnJvdW5kaW5nIHRyYW5zYWN0aW9uIGNvbW1pdHMuXG4gICAqIElmIG5vIHRyYW5zYWN0aW9uIGlzIGFjdGl2ZSwgdGhlIGNhbGxiYWNrIHJ1bnMgaW1tZWRpYXRlbHkuXG4gICAqIEBwYXJhbSB7KCkgPT4gdm9pZCB8IFByb21pc2U8dm9pZD59IGNhbGxiYWNrIC0gQ2FsbGJhY2suXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIHdoZW4gdGhlIGNhbGxiYWNrIGhhcyBiZWVuIHJlZ2lzdGVyZWQgb3IgcnVuLlxuICAgKi9cbiAgYXN5bmMgYWZ0ZXJDb21taXQoY2FsbGJhY2spIHtcbiAgICBjb25zdCBjdXJyZW50RnJhbWUgPSB0aGlzLl9hZnRlckNvbW1pdENhbGxiYWNrRnJhbWVzW3RoaXMuX2FmdGVyQ29tbWl0Q2FsbGJhY2tGcmFtZXMubGVuZ3RoIC0gMV1cblxuICAgIGlmICghY3VycmVudEZyYW1lKSB7XG4gICAgICBhd2FpdCBjYWxsYmFjaygpXG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICBjdXJyZW50RnJhbWUucHVzaChjYWxsYmFjaylcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHN0YXJ0IHRyYW5zYWN0aW9uLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBSZXNvbHZlcyB3aGVuIGNvbXBsZXRlLlxuICAgKi9cbiAgYXN5bmMgc3RhcnRUcmFuc2FjdGlvbigpIHtcbiAgICBhd2FpdCB0aGlzLl90cmFuc2FjdGlvbnNBY3Rpb25zTXV0ZXguc3luYyhhc3luYyAoKSA9PiB7XG4gICAgICBhd2FpdCB0aGlzLl9zdGFydFRyYW5zYWN0aW9uQWN0aW9uKClcbiAgICAgIHRoaXMuX3RyYW5zYWN0aW9uc0NvdW50KytcbiAgICB9KVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgc3RhcnQgdHJhbnNhY3Rpb24gYWN0aW9uLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBSZXNvbHZlcyB3aGVuIGNvbXBsZXRlLlxuICAgKi9cbiAgYXN5bmMgX3N0YXJ0VHJhbnNhY3Rpb25BY3Rpb24oKSB7XG4gICAgYXdhaXQgdGhpcy5xdWVyeShcIkJFR0lOIFRSQU5TQUNUSU9OXCIpXG4gIH1cblxuICAvKipcbiAgICogUnVucyBjb21taXQgdHJhbnNhY3Rpb24uXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIHdoZW4gY29tcGxldGUuXG4gICAqL1xuICBhc3luYyBjb21taXRUcmFuc2FjdGlvbigpIHtcbiAgICBhd2FpdCB0aGlzLl90cmFuc2FjdGlvbnNBY3Rpb25zTXV0ZXguc3luYyhhc3luYyAoKSA9PiB7XG4gICAgICBhd2FpdCB0aGlzLl9jb21taXRUcmFuc2FjdGlvbkFjdGlvbigpXG4gICAgICB0aGlzLl90cmFuc2FjdGlvbnNDb3VudC0tXG4gICAgfSlcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGNvbW1pdCB0cmFuc2FjdGlvbiBhY3Rpb24uXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIHdoZW4gY29tcGxldGUuXG4gICAqL1xuICBhc3luYyBfY29tbWl0VHJhbnNhY3Rpb25BY3Rpb24oKSB7XG4gICAgYXdhaXQgdGhpcy5xdWVyeShcIkNPTU1JVFwiKVxuICB9XG5cbiAgLyoqXG4gICAqIE1lcmdlcyBjb21taXR0ZWQgY2FsbGJhY2tzIGludG8gdGhlIHBhcmVudCB0cmFuc2FjdGlvbiBmcmFtZSBvciBydW5zIHRoZW0gd2hlbiB0aGUgb3V0ZXJtb3N0IGNvbW1pdCBjb21wbGV0ZXMuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIHdoZW4gY29tcGxldGUuXG4gICAqL1xuICBhc3luYyBfY29tbWl0QWZ0ZXJDb21taXRDYWxsYmFja0ZyYW1lKCkge1xuICAgIGNvbnN0IGNvbW1pdHRlZENhbGxiYWNrcyA9IHRoaXMuX2FmdGVyQ29tbWl0Q2FsbGJhY2tGcmFtZXMucG9wKClcblxuICAgIGlmICghY29tbWl0dGVkQ2FsbGJhY2tzIHx8IGNvbW1pdHRlZENhbGxiYWNrcy5sZW5ndGggPT09IDApIHJldHVyblxuXG4gICAgY29uc3QgcGFyZW50RnJhbWUgPSB0aGlzLl9hZnRlckNvbW1pdENhbGxiYWNrRnJhbWVzW3RoaXMuX2FmdGVyQ29tbWl0Q2FsbGJhY2tGcmFtZXMubGVuZ3RoIC0gMV1cblxuICAgIGlmIChwYXJlbnRGcmFtZSkge1xuICAgICAgcGFyZW50RnJhbWUucHVzaCguLi5jb21taXR0ZWRDYWxsYmFja3MpXG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IGNhbGxiYWNrIG9mIGNvbW1pdHRlZENhbGxiYWNrcykge1xuICAgICAgYXdhaXQgY2FsbGJhY2soKVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHF1ZXJ5LlxuICAgKiBAcGFyYW0ge3N0cmluZ30gc3FsIC0gU1FMIHN0cmluZy5cbiAgICogQHBhcmFtIHtRdWVyeU9wdGlvbnN9IFtvcHRpb25zXSAtIFF1ZXJ5IG9wdGlvbnMuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPFF1ZXJ5UmVzdWx0VHlwZT59IC0gUmVzb2x2ZXMgd2l0aCB0aGUgcXVlcnkuXG4gICAqL1xuICBhc3luYyBxdWVyeShzcWwsIG9wdGlvbnMgPSB7fSkge1xuICAgIHRoaXMuX2Fzc2VydFdyaXRhYmxlUXVlcnkoc3FsKVxuXG4gICAgbGV0IHRyaWVzID0gMFxuICAgIGNvbnN0IG1heFRyaWVzID0gNVxuICAgIGNvbnN0IHJlcXVlc3RUaW1pbmcgPSB0aGlzLmNvbmZpZ3VyYXRpb24uZ2V0Q3VycmVudFJlcXVlc3RUaW1pbmcoKVxuICAgIGNvbnN0IGxvZ1F1ZXJ5ID0gb3B0aW9ucy5sb2dRdWVyeSA/PyB0aGlzLl9xdWVyeUxvZ2dpbmdFbmFibGVkKClcbiAgICBjb25zdCBzb3VyY2VTdGFjayA9IGxvZ1F1ZXJ5ID8gKG9wdGlvbnMuc291cmNlU3RhY2sgfHwgRXJyb3IoKS5zdGFjaykgOiB1bmRlZmluZWRcbiAgICBjb25zdCBxdWVyeVNxbCA9IHRoaXMuX3F1ZXJ5U3FsV2l0aFByb2Nlc3NMaXN0Q29tbWVudChzcWwsIG9wdGlvbnMpXG5cbiAgICB3aGlsZSAodHJpZXMgPCBtYXhUcmllcykge1xuICAgICAgdHJpZXMrK1xuXG4gICAgICB0cnkge1xuICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5fcXVlcnlBY3R1YWxXaXRoTG9nZ2luZyh7b3JpZ2luYWxTcWw6IHNxbCwgcXVlcnlTcWx9LCB7Li4ub3B0aW9ucywgbG9nUXVlcnksIHNvdXJjZVN0YWNrfSwgcmVxdWVzdFRpbWluZywgdHJpZXMpXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBpZiAoIShlcnJvciBpbnN0YW5jZW9mIEVycm9yKSkgdGhyb3cgZXJyb3JcblxuICAgICAgICBjb25zdCByZXRyeUluZm8gPSB0aGlzLnJldHJ5YWJsZURhdGFiYXNlRXJyb3IoZXJyb3IpXG5cbiAgICAgICAgaWYgKHRyaWVzIDwgbWF4VHJpZXMgJiYgcmV0cnlJbmZvLnJldHJ5KSB7XG4gICAgICAgICAgaWYgKHJldHJ5SW5mby5yZWNvbm5lY3QpIHtcbiAgICAgICAgICAgIGlmICh0aGlzLl90cmFuc2FjdGlvbnNDb3VudCA+IDApIHtcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBDYW5ub3QgcmVjb25uZWN0IHdoaWxlIGEgdHJhbnNhY3Rpb24gaXMgYWN0aXZlICgke3RoaXMuX3RyYW5zYWN0aW9uc0NvdW50fSkuIE9yaWdpbmFsIGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCwge2NhdXNlOiBlcnJvcn0pXG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGF3YWl0IHRoaXMucmVjb25uZWN0KClcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjb25zdCB3YWl0TXMgPSB0eXBlb2YgcmV0cnlJbmZvLndhaXRNcyA9PT0gXCJudW1iZXJcIiAmJiBOdW1iZXIuaXNGaW5pdGUocmV0cnlJbmZvLndhaXRNcykgPyByZXRyeUluZm8ud2FpdE1zIDogMTAwXG5cbiAgICAgICAgICBpZiAod2FpdE1zID4gMCkgYXdhaXQgd2FpdCh3YWl0TXMpXG4gICAgICAgICAgdGhpcy5sb2dnZXIud2FybihgUmV0cnlpbmcgcXVlcnkgYmVjYXVzZSBmYWlsZWQgd2l0aDogJHtlcnJvci5zdGFja31gKVxuICAgICAgICAgIC8vIFJldHJ5XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhyb3cgZXJyb3JcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHRocm93IG5ldyBFcnJvcihcIidxdWVyeScgdW5leHBlY3RlZCBjYW1lIGhlcmVcIilcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHF1ZXJ5IGFjdHVhbCB3aXRoIGxvZ2dpbmcuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gT3B0aW9ucyBvYmplY3QuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhcmdzLm9yaWdpbmFsU3FsIC0gT3JpZ2luYWwgU1FMIHN0cmluZyBiZWZvcmUgcHJvY2Vzcy1saXN0IGNvbW1lbnRzLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gYXJncy5xdWVyeVNxbCAtIFNRTCBzdHJpbmcgc2VudCB0byB0aGUgZGF0YWJhc2UuXG4gICAqIEBwYXJhbSB7UXVlcnlPcHRpb25zfSBvcHRpb25zIC0gUXVlcnkgb3B0aW9ucy5cbiAgICogQHBhcmFtIHtpbXBvcnQoXCIuLi8uLi9odHRwLXNlcnZlci9jbGllbnQvcmVxdWVzdC10aW1pbmcuanNcIikuZGVmYXVsdCB8IHVuZGVmaW5lZH0gcmVxdWVzdFRpbWluZyAtIFJlcXVlc3QgdGltaW5nLlxuICAgKiBAcGFyYW0ge251bWJlcn0gdHJpZXMgLSBRdWVyeSBhdHRlbXB0IGNvdW50LlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxRdWVyeVJlc3VsdFR5cGU+fSAtIFJlc29sdmVzIHdpdGggdGhlIHF1ZXJ5LlxuICAgKi9cbiAgYXN5bmMgX3F1ZXJ5QWN0dWFsV2l0aExvZ2dpbmcoe29yaWdpbmFsU3FsLCBxdWVyeVNxbH0sIG9wdGlvbnMsIHJlcXVlc3RUaW1pbmcsIHRyaWVzKSB7XG4gICAgY29uc3Qgc3RhcnRlZEF0TXMgPSBub3dNcygpXG4gICAgY29uc3QgcHJldmlvdXNBY3RpdmVRdWVyeSA9IHRoaXMuX2FjdGl2ZVF1ZXJ5XG4gICAgdGhpcy5fYWN0aXZlUXVlcnkgPSB7XG4gICAgICBhbm5vdGF0aW9uczogZ2V0RGF0YWJhc2VBbm5vdGF0aW9ucygpLFxuICAgICAgbG9nTmFtZTogb3B0aW9ucy5sb2dOYW1lIHx8IFwiU1FMXCIsXG4gICAgICBzcWxQcmV2aWV3OiB0aGlzLl9kZWJ1Z1NxbFByZXZpZXcob3JpZ2luYWxTcWwpLFxuICAgICAgc3RhcnRlZEF0VW5peE1zOiBEYXRlLm5vdygpXG4gICAgfVxuICAgIGxldCByZXN1bHRcblxuICAgIHRyeSB7XG4gICAgICBpZiAocmVxdWVzdFRpbWluZyAmJiB0cmllcyA9PT0gMSkge1xuICAgICAgICByZXN1bHQgPSBhd2FpdCByZXF1ZXN0VGltaW5nLm1lYXN1cmVEYlF1ZXJ5KGFzeW5jICgpID0+IGF3YWl0IHRoaXMuX3F1ZXJ5QWN0dWFsKHF1ZXJ5U3FsKSlcbiAgICAgIH0gZWxzZSBpZiAocmVxdWVzdFRpbWluZykge1xuICAgICAgICByZXN1bHQgPSBhd2FpdCByZXF1ZXN0VGltaW5nLm1lYXN1cmUoXCJkYlwiLCBhc3luYyAoKSA9PiBhd2FpdCB0aGlzLl9xdWVyeUFjdHVhbChxdWVyeVNxbCkpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXN1bHQgPSBhd2FpdCB0aGlzLl9xdWVyeUFjdHVhbChxdWVyeVNxbClcbiAgICAgIH1cbiAgICB9IGZpbmFsbHkge1xuICAgICAgdGhpcy5fYWN0aXZlUXVlcnkgPSBwcmV2aW91c0FjdGl2ZVF1ZXJ5XG4gICAgfVxuXG4gICAgY29uc3QgZWxhcHNlZE1zID0gbm93TXMoKSAtIHN0YXJ0ZWRBdE1zXG5cbiAgICBpZiAob3B0aW9ucy5sb2dRdWVyeSAhPT0gZmFsc2UpIHtcbiAgICAgIGF3YWl0IHRoaXMuX2xvZ1F1ZXJ5KHtcbiAgICAgICAgZWxhcHNlZE1zLFxuICAgICAgICBsb2dOYW1lOiBvcHRpb25zLmxvZ05hbWUgfHwgXCJTUUxcIixcbiAgICAgICAgc291cmNlU3RhY2s6IG9wdGlvbnMuc291cmNlU3RhY2ssXG4gICAgICAgIHNxbDogb3JpZ2luYWxTcWxcbiAgICAgIH0pXG4gICAgfVxuXG4gICAgaWYgKHRoaXMuX3NjaGVtYUNhY2hlSW52YWxpZGF0aW5nU3FsKG9yaWdpbmFsU3FsKSkge1xuICAgICAgdGhpcy5jbGVhclNjaGVtYUNhY2hlKClcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzdWx0XG4gIH1cblxuICAvKipcbiAgICogUnVucyBnZXQgZGVidWcgc25hcHNob3QuXG4gICAqIEByZXR1cm5zIHtEYXRhYmFzZUNvbm5lY3Rpb25EZWJ1Z1NuYXBzaG90fSAtIERpYWdub3N0aWMgc25hcHNob3QgZm9yIHRoaXMgY29ubmVjdGlvbi5cbiAgICovXG4gIGdldERlYnVnU25hcHNob3QoKSB7XG4gICAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKVxuICAgIGNvbnN0IGFjdGl2ZVF1ZXJ5ID0gdGhpcy5fYWN0aXZlUXVlcnlcblxuICAgIHJldHVybiB7XG4gICAgICBhY3RpdmVRdWVyeTogYWN0aXZlUXVlcnkgPyB7Li4uYWN0aXZlUXVlcnksIHJ1bm5pbmdNczogTWF0aC5tYXgoMCwgbm93IC0gYWN0aXZlUXVlcnkuc3RhcnRlZEF0VW5peE1zKX0gOiBudWxsLFxuICAgICAgY2hlY2tvdXRBZ2VNczogdGhpcy5fY29ubmVjdGlvbkNoZWNrZWRPdXRBdFVuaXhNcyA/IE1hdGgubWF4KDAsIG5vdyAtIHRoaXMuX2Nvbm5lY3Rpb25DaGVja2VkT3V0QXRVbml4TXMpIDogdW5kZWZpbmVkLFxuICAgICAgY2hlY2tlZE91dEF0VW5peE1zOiB0aGlzLl9jb25uZWN0aW9uQ2hlY2tlZE91dEF0VW5peE1zLFxuICAgICAgY2hlY2tvdXROYW1lOiB0aGlzLl9jb25uZWN0aW9uQ2hlY2tvdXROYW1lLFxuICAgICAgZHJpdmVyQ2xhc3M6IHRoaXMuY29uc3RydWN0b3IubmFtZSxcbiAgICAgIGlkU2VxOiB0aGlzLmlkU2VxLFxuICAgICAgb3BlblRyYW5zYWN0aW9uczogdGhpcy5fdHJhbnNhY3Rpb25zQ291bnQsXG4gICAgICBzY2hlbWFDYWNoZUVudHJpZXM6IHRoaXMuX3NjaGVtYUNhY2hlLnNpemVcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUnVucyBkZWJ1ZyBzcWwgcHJldmlldy5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHNxbCAtIFNRTCB0byBwcmV2aWV3LlxuICAgKiBAcmV0dXJucyB7c3RyaW5nfSAtIE5vcm1hbGl6ZWQgdHJ1bmNhdGVkIFNRTCBwcmV2aWV3IGZvciBkaWFnbm9zdGljcy5cbiAgICovXG4gIF9kZWJ1Z1NxbFByZXZpZXcoc3FsKSB7XG4gICAgcmV0dXJuIHNxbFxuICAgICAgLnJlcGxhY2UoL1xccysvZywgXCIgXCIpXG4gICAgICAudHJpbSgpXG4gICAgICAuc2xpY2UoMCwgNTAwKVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgcXVlcnkgc3FsIHdpdGggcHJvY2VzcyBsaXN0IGNvbW1lbnQuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBzcWwgLSBTUUwgc3RyaW5nLlxuICAgKiBAcGFyYW0ge1F1ZXJ5T3B0aW9uc30gb3B0aW9ucyAtIFF1ZXJ5IG9wdGlvbnMuXG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IC0gU1FMIHN0cmluZyB3aXRoIGEgbGVhZGluZyBwcm9jZXNzLWxpc3QgY29tbWVudCB3aGVuIGFubm90YXRpb25zIGV4aXN0LlxuICAgKi9cbiAgX3F1ZXJ5U3FsV2l0aFByb2Nlc3NMaXN0Q29tbWVudChzcWwsIG9wdGlvbnMpIHtcbiAgICBpZiAob3B0aW9ucy5wcm9jZXNzTGlzdENvbW1lbnQgPT09IGZhbHNlKSByZXR1cm4gc3FsXG5cbiAgICBjb25zdCBwYXJ0cyA9IFtdXG5cbiAgICBpZiAodGhpcy5fY29ubmVjdGlvbkNoZWNrb3V0TmFtZSkge1xuICAgICAgcGFydHMucHVzaChgY2hlY2tvdXQ9XCIke3RoaXMuX3Byb2Nlc3NMaXN0Q29tbWVudFZhbHVlKHRoaXMuX2Nvbm5lY3Rpb25DaGVja291dE5hbWUpfVwiYClcbiAgICB9XG5cbiAgICBjb25zdCBhbm5vdGF0aW9ucyA9IGdldERhdGFiYXNlQW5ub3RhdGlvbnMoKVxuXG4gICAgaWYgKGFubm90YXRpb25zLmxlbmd0aCA+IDApIHtcbiAgICAgIHBhcnRzLnB1c2goYGFubm90YXRpb25zPVwiJHt0aGlzLl9wcm9jZXNzTGlzdENvbW1lbnRWYWx1ZShhbm5vdGF0aW9ucy5qb2luKFwiID4gXCIpKX1cImApXG4gICAgfVxuXG4gICAgaWYgKHBhcnRzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIHNxbFxuXG4gICAgcmV0dXJuIGAvKiB2ZWxvY2lvdXMgJHtwYXJ0cy5qb2luKFwiIFwiKX0gKi8gJHtzcWx9YFxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgcHJvY2VzcyBsaXN0IGNvbW1lbnQgdmFsdWUuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB2YWx1ZSAtIFJhdyBwcm9jZXNzLWxpc3QgY29tbWVudCB2YWx1ZS5cbiAgICogQHJldHVybnMge3N0cmluZ30gLSBTYW5pdGl6ZWQgcHJvY2Vzcy1saXN0IGNvbW1lbnQgdmFsdWUuXG4gICAqL1xuICBfcHJvY2Vzc0xpc3RDb21tZW50VmFsdWUodmFsdWUpIHtcbiAgICBsZXQgc2FuaXRpemVkID0gXCJcIlxuXG4gICAgZm9yIChjb25zdCBjaGFyYWN0ZXIgb2YgdmFsdWUpIHtcbiAgICAgIGNvbnN0IGNvZGVQb2ludCA9IGNoYXJhY3Rlci5jb2RlUG9pbnRBdCgwKVxuXG4gICAgICBzYW5pdGl6ZWQgKz0gY29kZVBvaW50ICE9PSB1bmRlZmluZWQgJiYgKGNvZGVQb2ludCA8IDMyIHx8IGNvZGVQb2ludCA9PT0gMTI3KSA/IFwiIFwiIDogY2hhcmFjdGVyXG4gICAgfVxuXG4gICAgcmV0dXJuIHNhbml0aXplZFxuICAgICAgLnJlcGxhY2UoL1xcKlxcLy9nLCBcIiogL1wiKVxuICAgICAgLnJlcGxhY2UoL1xccysvZywgXCIgXCIpXG4gICAgICAudHJpbSgpXG4gICAgICAuc2xpY2UoMCwgMjAwKVxuICAgICAgLnJlcGxhY2UoL1wiL2csIFwiJ1wiKVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgc2NoZW1hIGNhY2hlIGludmFsaWRhdGluZyBzcWwuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBzcWwgLSBTUUwgc3RyaW5nLlxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBXaGV0aGVyIHRoZSBTUUwgc2hvdWxkIGludmFsaWRhdGUgc2NoZW1hIG1ldGFkYXRhLlxuICAgKi9cbiAgX3NjaGVtYUNhY2hlSW52YWxpZGF0aW5nU3FsKHNxbCkge1xuICAgIGNvbnN0IG5vcm1hbGl6ZWQgPSBzcWxcbiAgICAgIC50cmltKClcbiAgICAgIC5yZXBsYWNlKC9eXFx1ZmVmZi8sIFwiXCIpXG4gICAgICAucmVwbGFjZSgvXFwvXFwqW1xcc1xcU10qP1xcKlxcLy9nLCBcIiBcIilcbiAgICAgIC5yZXBsYWNlKC8tLVteXFxuXSooXFxufCQpL2csIFwiIFwiKVxuICAgICAgLnJlcGxhY2UoL1xccysvZywgXCIgXCIpXG4gICAgICAudG9Mb3dlckNhc2UoKVxuXG4gICAgaWYgKCFub3JtYWxpemVkKSByZXR1cm4gZmFsc2VcbiAgICBpZiAoL14oY3JlYXRlfGFsdGVyfGRyb3B8cmVuYW1lKVxcYi8udGVzdChub3JtYWxpemVkKSkgcmV0dXJuIHRydWVcbiAgICBpZiAoL15jb21tZW50XFxzK29uXFxiLy50ZXN0KG5vcm1hbGl6ZWQpKSByZXR1cm4gdHJ1ZVxuICAgIGlmICgvXmV4ZWMoPzp1dGUpP1xccytzcF9yZW5hbWVcXGIvLnRlc3Qobm9ybWFsaXplZCkpIHJldHVybiB0cnVlXG4gICAgaWYgKC9eaWZcXGJbXFxzXFxTXSpcXGJiZWdpblxccysoY3JlYXRlfGFsdGVyfGRyb3B8cmVuYW1lKVxcYi8udGVzdChub3JtYWxpemVkKSkgcmV0dXJuIHRydWVcblxuICAgIHJldHVybiBmYWxzZVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgcXVlcnkgbG9nZ2luZyBlbmFibGVkLlxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBXaGV0aGVyIHF1ZXJ5IGxvZ2dpbmcgaXMgZW5hYmxlZCBmb3IgdGhpcyBkcml2ZXIuXG4gICAqL1xuICBfcXVlcnlMb2dnaW5nRW5hYmxlZCgpIHtcbiAgICBpZiAodHlwZW9mIHRoaXMuY29uZmlndXJhdGlvbj8uZ2V0UXVlcnlMb2dnaW5nRW5hYmxlZCAhPT0gXCJmdW5jdGlvblwiKSByZXR1cm4gdHJ1ZVxuICAgIGlmICghdGhpcy5jb25maWd1cmF0aW9uLmdldFF1ZXJ5TG9nZ2luZ0VuYWJsZWQoKSkgcmV0dXJuIGZhbHNlXG5cbiAgICBjb25zdCBsb2dnZXIgPSBuZXcgTG9nZ2VyKFwiU1FMXCIsIHtjb25maWd1cmF0aW9uOiB0aGlzLmNvbmZpZ3VyYXRpb259KVxuXG4gICAgcmV0dXJuIGxvZ2dlci5pc0xldmVsRW5hYmxlZChcImluZm9cIilcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGxvZyBxdWVyeS5cbiAgICogQHBhcmFtIHtvYmplY3R9IGFyZ3MgLSBPcHRpb25zIG9iamVjdC5cbiAgICogQHBhcmFtIHtudW1iZXJ9IGFyZ3MuZWxhcHNlZE1zIC0gRWxhcHNlZCBtaWxsaXNlY29uZHMuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhcmdzLmxvZ05hbWUgLSBRdWVyeSBsb2cgc3ViamVjdC5cbiAgICogQHBhcmFtIHtzdHJpbmcgfCB1bmRlZmluZWR9IGFyZ3Muc291cmNlU3RhY2sgLSBTb3VyY2Ugc3RhY2suXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhcmdzLnNxbCAtIFNRTCBzdHJpbmcuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIHdoZW4gY29tcGxldGUuXG4gICAqL1xuICBhc3luYyBfbG9nUXVlcnkoe2VsYXBzZWRNcywgbG9nTmFtZSwgc291cmNlU3RhY2ssIHNxbH0pIHtcbiAgICBjb25zdCBsb2dnZXIgPSBuZXcgTG9nZ2VyKGxvZ05hbWUsIHtjb25maWd1cmF0aW9uOiB0aGlzLmNvbmZpZ3VyYXRpb259KVxuICAgIGNvbnN0IHNvdXJjZUxpbmUgPSB0aGlzLl9xdWVyeVNvdXJjZUxpbmUoc291cmNlU3RhY2spXG4gICAgY29uc3QgbWVzc2FnZSA9IHNvdXJjZUxpbmVcbiAgICAgID8gYCgke2Zvcm1hdEVsYXBzZWRNcyhlbGFwc2VkTXMpfSkgICR7c3FsfVxcbiAg4oazICR7c291cmNlTGluZX1gXG4gICAgICA6IGAoJHtmb3JtYXRFbGFwc2VkTXMoZWxhcHNlZE1zKX0pICAke3NxbH1gXG5cbiAgICBhd2FpdCBsb2dnZXIuaW5mbyhtZXNzYWdlKVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgcXVlcnkgc291cmNlIGxpbmUuXG4gICAqIEBwYXJhbSB7c3RyaW5nIHwgdW5kZWZpbmVkfSBzb3VyY2VTdGFjayAtIFNvdXJjZSBzdGFjay5cbiAgICogQHJldHVybnMge3N0cmluZyB8IHVuZGVmaW5lZH0gLSBTb3VyY2UgbGluZSB3aGVuIGFuIGFwcGxpY2F0aW9uIGZyYW1lIGlzIGF2YWlsYWJsZS5cbiAgICovXG4gIF9xdWVyeVNvdXJjZUxpbmUoc291cmNlU3RhY2spIHtcbiAgICBpZiAoIXNvdXJjZVN0YWNrKSByZXR1cm4gdW5kZWZpbmVkXG5cbiAgICBjb25zdCBhcHBsaWNhdGlvbkRpcmVjdG9yeSA9IHR5cGVvZiB0aGlzLmNvbmZpZ3VyYXRpb24/LmdldERpcmVjdG9yeUlmQXZhaWxhYmxlID09PSBcImZ1bmN0aW9uXCJcbiAgICAgID8gdGhpcy5jb25maWd1cmF0aW9uLmdldERpcmVjdG9yeUlmQXZhaWxhYmxlKClcbiAgICAgIDogdGhpcy5jb25maWd1cmF0aW9uPy5nZXREaXJlY3Rvcnk/LigpXG5cbiAgICBpZiAoIWFwcGxpY2F0aW9uRGlyZWN0b3J5KSByZXR1cm4gdW5kZWZpbmVkXG5cbiAgICBjb25zdCBlcnJvciA9IG5ldyBFcnJvcihcIlF1ZXJ5IHNvdXJjZVwiKVxuXG4gICAgZXJyb3Iuc3RhY2sgPSBzb3VyY2VTdGFja1xuXG4gICAgcmV0dXJuIEJhY2t0cmFjZUNsZWFuZXIuZ2V0QXBwbGljYXRpb25Tb3VyY2VMaW5lKGVycm9yLCB7XG4gICAgICBhcHBsaWNhdGlvbkRpcmVjdG9yeSxcbiAgICAgIGZyYW1ld29ya1NvdXJjZURpcmVjdG9yeTogdGhpcy5jb25maWd1cmF0aW9uLmdldEVudmlyb25tZW50SGFuZGxlcigpLmdldEZyYW1ld29ya1NvdXJjZURpcmVjdG9yeSgpXG4gICAgfSlcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHF1ZXJ5IGFjdHVhbC5cbiAgICogQGFic3RyYWN0XG4gICAqIEBwYXJhbSB7c3RyaW5nfSBzcWwgLSBTUUwgc3RyaW5nLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxRdWVyeVJlc3VsdFR5cGU+fSAtIFJlc29sdmVzIHdpdGggdGhlIHF1ZXJ5IGFjdHVhbC5cbiAgICovXG4gIF9xdWVyeUFjdHVhbChzcWwpIHsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby11bnVzZWQtdmFyc1xuICAgIHRocm93IG5ldyBFcnJvcihgcXVlcnlBY3R1YWwgbm90IGltcGxlbWVudGVkYClcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHF1ZXJ5IHRvIHNxbC5cbiAgICogQGFic3RyYWN0XG4gICAqIEBwYXJhbSB7UXVlcnl9IF9xdWVyeSAtIFF1ZXJ5IGluc3RhbmNlLlxuICAgKiBAcmV0dXJucyB7c3RyaW5nfSAtIFNRTCBzdHJpbmcuXG4gICAqL1xuICBxdWVyeVRvU3FsKF9xdWVyeSkgeyB0aHJvdyBuZXcgRXJyb3IoXCJxdWVyeVRvU3FsIG5vdCBpbXBsZW1lbnRlZFwiKSB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgcmV0cnlhYmxlIGRhdGFiYXNlIGVycm9yLlxuICAgKiBAcGFyYW0ge0Vycm9yfSBfZXJyb3IgLSBFcnJvciBpbnN0YW5jZS5cbiAgICogQHJldHVybnMge1JldHJ5YWJsZURhdGFiYXNlRXJyb3JSZXN1bHR9IC0gUmV0cnkgaW5mby5cbiAgICovXG4gIHJldHJ5YWJsZURhdGFiYXNlRXJyb3IoX2Vycm9yKSB7XG4gICAgcmV0dXJuIHtyZXRyeTogZmFsc2UsIHJlY29ubmVjdDogZmFsc2V9XG4gIH1cblxuICAvKipcbiAgICogUnVucyBhc3NlcnQgd3JpdGFibGUgcXVlcnkuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBzcWwgLSBTUUwgc3RyaW5nLlxuICAgKiBAcmV0dXJucyB7dm9pZH0gLSBObyByZXR1cm4gdmFsdWUuXG4gICAqL1xuICBfYXNzZXJ0V3JpdGFibGVRdWVyeShzcWwpIHtcbiAgICBpZiAoIXRoaXMuaXNSZWFkT25seSgpKSByZXR1cm5cbiAgICBpZiAoIXRoaXMuX3NxbExvb2tzTGlrZVdyaXRlKHNxbCkpIHJldHVyblxuXG4gICAgdGhyb3cgbmV3IEVycm9yKFwiRGF0YWJhc2UgaXMgcmVhZC1vbmx5XCIpXG4gIH1cblxuICAvKipcbiAgICogUnVucyBhc3NlcnQgbm90IHJlYWQgb25seS5cbiAgICogQHJldHVybnMge3ZvaWR9IC0gTm8gcmV0dXJuIHZhbHVlLlxuICAgKi9cbiAgX2Fzc2VydE5vdFJlYWRPbmx5KCkge1xuICAgIGlmICh0aGlzLmlzUmVhZE9ubHkoKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiRGF0YWJhc2UgaXMgcmVhZC1vbmx5XCIpXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgc3FsIGxvb2tzIGxpa2Ugd3JpdGUuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBzcWwgLSBTUUwgc3RyaW5nLlxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBTUUwgcmVwcmVzZW50YXRpb24uXG4gICAqL1xuICBfc3FsTG9va3NMaWtlV3JpdGUoc3FsKSB7XG4gICAgY29uc3Qgbm9ybWFsaXplZCA9IHNxbC50cmltKCkudG9Mb3dlckNhc2UoKVxuXG4gICAgaWYgKCFub3JtYWxpemVkKSByZXR1cm4gZmFsc2VcblxuICAgIGlmIChcbiAgICAgIG5vcm1hbGl6ZWQuc3RhcnRzV2l0aChcInNlbGVjdFwiKSB8fFxuICAgICAgbm9ybWFsaXplZC5zdGFydHNXaXRoKFwic2hvd1wiKSB8fFxuICAgICAgbm9ybWFsaXplZC5zdGFydHNXaXRoKFwicHJhZ21hXCIpIHx8XG4gICAgICBub3JtYWxpemVkLnN0YXJ0c1dpdGgoXCJleHBsYWluXCIpIHx8XG4gICAgICBub3JtYWxpemVkLnN0YXJ0c1dpdGgoXCJkZXNjcmliZVwiKVxuICAgICkge1xuICAgICAgcmV0dXJuIGZhbHNlXG4gICAgfVxuXG4gICAgaWYgKG5vcm1hbGl6ZWQuc3RhcnRzV2l0aChcIndpdGhcIikpIHtcbiAgICAgIGNvbnN0IHdpdGhNYXRjaCA9IG5vcm1hbGl6ZWQubWF0Y2goL15cXHMqd2l0aFtcXHNcXFNdKz9cXClcXHMqKHNlbGVjdHxpbnNlcnR8dXBkYXRlfGRlbGV0ZXxtZXJnZXxyZXBsYWNlKVxcYi8pXG5cbiAgICAgIGlmICh3aXRoTWF0Y2gpIHtcbiAgICAgICAgcmV0dXJuIHdpdGhNYXRjaFsxXSAhPT0gXCJzZWxlY3RcIlxuICAgICAgfVxuXG4gICAgICByZXR1cm4gZmFsc2VcbiAgICB9XG5cbiAgICBjb25zdCBrZXl3b3JkTWF0Y2ggPSBub3JtYWxpemVkLm1hdGNoKC9eXFxzKihcXHcrKS8pXG4gICAgY29uc3Qga2V5d29yZCA9IGtleXdvcmRNYXRjaCA/IGtleXdvcmRNYXRjaFsxXSA6IFwiXCJcblxuICAgIHJldHVybiBbXG4gICAgICBcImluc2VydFwiLFxuICAgICAgXCJ1cGRhdGVcIixcbiAgICAgIFwiZGVsZXRlXCIsXG4gICAgICBcImNyZWF0ZVwiLFxuICAgICAgXCJhbHRlclwiLFxuICAgICAgXCJkcm9wXCIsXG4gICAgICBcInRydW5jYXRlXCIsXG4gICAgICBcIm1lcmdlXCIsXG4gICAgICBcInJlcGxhY2VcIlxuICAgIF0uaW5jbHVkZXMoa2V5d29yZClcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGlzIHJlYWQgb25seS5cbiAgICogQHJldHVybnMge2Jvb2xlYW59IC0gV2hldGhlciByZWFkIG9ubHkuXG4gICAqL1xuICBpc1JlYWRPbmx5KCkge1xuICAgIHJldHVybiBCb29sZWFuKHRoaXMuZ2V0QXJncygpLnJlYWRPbmx5KVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgcm9sbGJhY2sgdHJhbnNhY3Rpb24uXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIHdoZW4gY29tcGxldGUuXG4gICAqL1xuICBhc3luYyByb2xsYmFja1RyYW5zYWN0aW9uKCkge1xuICAgIGF3YWl0IHRoaXMuX3RyYW5zYWN0aW9uc0FjdGlvbnNNdXRleC5zeW5jKGFzeW5jICgpID0+IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHRoaXMuX3JvbGxiYWNrVHJhbnNhY3Rpb25BY3Rpb24oKVxuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgdGhpcy5fdHJhbnNhY3Rpb25zQ291bnQtLVxuXG4gICAgICAgIC8vIEEgcm9sbGVkLWJhY2sgdHJhbnNhY3Rpb24gbWF5IGhhdmUgcmV2ZXJ0ZWQgRERMIChlLmcuIGEgQ1JFQVRFIFRBQkxFXG4gICAgICAgIC8vIHJ1biBsYXppbHkgaW5zaWRlIHRoZSB0cmFuc2FjdGlvbiksIHNvIGFueSBjYWNoZWQgc2NoZW1hIG1ldGFkYXRhIGlzXG4gICAgICAgIC8vIG5vdyBzdGFsZSBhbmQgbXVzdCBiZSBpbnZhbGlkYXRlZC4gV2l0aG91dCB0aGlzLCBhIGxhdGVyIHRhYmxlRXhpc3RzKClcbiAgICAgICAgLy8gY2hlY2sgY2FuIHJlcG9ydCBhIHRhYmxlIHRoYXQgdGhlIHJvbGxiYWNrIGFscmVhZHkgcmVtb3ZlZCwgc28gY2FsbGVyc1xuICAgICAgICAvLyBza2lwIHJlY3JlYXRpbmcgaXQgYW5kIHRoZW4gZmFpbCB3aXRoIFwibm8gc3VjaCB0YWJsZVwiLlxuICAgICAgICB0aGlzLmNsZWFyU2NoZW1hQ2FjaGUoKVxuICAgICAgfVxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogUnVucyByb2xsYmFjayB0cmFuc2FjdGlvbiBhY3Rpb24uXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIHdoZW4gY29tcGxldGUuXG4gICAqL1xuICBhc3luYyBfcm9sbGJhY2tUcmFuc2FjdGlvbkFjdGlvbigpIHtcbiAgICBhd2FpdCB0aGlzLnF1ZXJ5KFwiUk9MTEJBQ0tcIilcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGdlbmVyYXRlIHNhdmUgcG9pbnQgbmFtZS5cbiAgICogQHJldHVybnMge3N0cmluZ30gLSBUaGUgZ2VuZXJhdGUgc2F2ZSBwb2ludCBuYW1lLlxuICAgKi9cbiAgZ2VuZXJhdGVTYXZlUG9pbnROYW1lKCkge1xuICAgIHJldHVybiBgc3Ake25ldyBVVUlEKDQpLmZvcm1hdCgpLnJlcGxhY2VBbGwoXCItXCIsIFwiXCIpfWBcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHN0YXJ0IHNhdmUgcG9pbnQuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBzYXZlUG9pbnROYW1lIC0gU2F2ZSBwb2ludCBuYW1lLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBSZXNvbHZlcyB3aGVuIGNvbXBsZXRlLlxuICAgKi9cbiAgYXN5bmMgc3RhcnRTYXZlUG9pbnQoc2F2ZVBvaW50TmFtZSkge1xuICAgIGF3YWl0IHRoaXMuX3RyYW5zYWN0aW9uc0FjdGlvbnNNdXRleC5zeW5jKGFzeW5jICgpID0+IHtcbiAgICAgIGF3YWl0IHRoaXMuX3N0YXJ0U2F2ZVBvaW50QWN0aW9uKHNhdmVQb2ludE5hbWUpXG4gICAgfSlcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHN0YXJ0IHNhdmUgcG9pbnQgYWN0aW9uLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gc2F2ZVBvaW50TmFtZSAtIFNhdmUgcG9pbnQgbmFtZS5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgd2hlbiBjb21wbGV0ZS5cbiAgICovXG4gIGFzeW5jIF9zdGFydFNhdmVQb2ludEFjdGlvbihzYXZlUG9pbnROYW1lKSB7XG4gICAgYXdhaXQgdGhpcy5xdWVyeShgU0FWRVBPSU5UICR7c2F2ZVBvaW50TmFtZX1gKVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgcmVuYW1lIGNvbHVtbi5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHRhYmxlTmFtZSAtIFRhYmxlIG5hbWUuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBvbGRDb2x1bW5OYW1lIC0gUHJldmlvdXMgY29sdW1uIG5hbWUuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBuZXdDb2x1bW5OYW1lIC0gTmV3IGNvbHVtbiBuYW1lLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBSZXNvbHZlcyB3aGVuIGNvbXBsZXRlLlxuICAgKi9cbiAgYXN5bmMgcmVuYW1lQ29sdW1uKHRhYmxlTmFtZSwgb2xkQ29sdW1uTmFtZSwgbmV3Q29sdW1uTmFtZSkge1xuICAgIHRoaXMuX2Fzc2VydE5vdFJlYWRPbmx5KClcbiAgICBjb25zdCB0YWJsZUNvbHVtbiA9IG5ldyBUYWJsZUNvbHVtbihvbGRDb2x1bW5OYW1lKVxuXG4gICAgdGFibGVDb2x1bW4uc2V0TmV3TmFtZShuZXdDb2x1bW5OYW1lKVxuXG4gICAgY29uc3QgdGFibGVEYXRhID0gbmV3IFRhYmxlRGF0YSh0YWJsZU5hbWUpXG5cbiAgICB0YWJsZURhdGEuYWRkQ29sdW1uKHRhYmxlQ29sdW1uKVxuXG4gICAgY29uc3QgYWx0ZXJUYWJsZVNRTHMgPSBhd2FpdCB0aGlzLmFsdGVyVGFibGVTUUxzKHRhYmxlRGF0YSlcblxuICAgIGZvciAoY29uc3QgYWx0ZXJUYWJsZVNRTCBvZiBhbHRlclRhYmxlU1FMcykge1xuICAgICAgYXdhaXQgdGhpcy5xdWVyeShhbHRlclRhYmxlU1FMKVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHJlbGVhc2Ugc2F2ZSBwb2ludC5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHNhdmVQb2ludE5hbWUgLSBTYXZlIHBvaW50IG5hbWUuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIHdoZW4gY29tcGxldGUuXG4gICAqL1xuICBhc3luYyByZWxlYXNlU2F2ZVBvaW50KHNhdmVQb2ludE5hbWUpIHtcbiAgICBhd2FpdCB0aGlzLl90cmFuc2FjdGlvbnNBY3Rpb25zTXV0ZXguc3luYyhhc3luYyAoKSA9PiB7XG4gICAgICBhd2FpdCB0aGlzLl9yZWxlYXNlU2F2ZVBvaW50QWN0aW9uKHNhdmVQb2ludE5hbWUpXG4gICAgfSlcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHJlbGVhc2Ugc2F2ZSBwb2ludCBhY3Rpb24uXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBzYXZlUG9pbnROYW1lIC0gU2F2ZSBwb2ludCBuYW1lLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBSZXNvbHZlcyB3aGVuIGNvbXBsZXRlLlxuICAgKi9cbiAgYXN5bmMgX3JlbGVhc2VTYXZlUG9pbnRBY3Rpb24oc2F2ZVBvaW50TmFtZSkge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLnF1ZXJ5KGBSRUxFQVNFIFNBVkVQT0lOVCAke3NhdmVQb2ludE5hbWV9YClcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc3QgbWVzc2FnZSA9IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogYCR7ZXJyb3J9YFxuXG4gICAgICAvLyBTYXZlcG9pbnQgbWF5IGFscmVhZHkgYmUgZ29uZSBpZiB0aGUgZGF0YWJhc2Ugcm9sbGVkIGJhY2sgYXV0b21hdGljYWxseVxuICAgICAgaWYgKG1lc3NhZ2UudG9Mb3dlckNhc2UoKS5pbmNsdWRlcyhcInNhdmVwb2ludFwiKSAmJiBtZXNzYWdlLnRvTG93ZXJDYXNlKCkuaW5jbHVkZXMoXCJkb2VzIG5vdCBleGlzdFwiKSkge1xuICAgICAgICB0aGlzLmxvZ2dlci5kZWJ1ZyhgUmVsZWFzZSBzYXZlcG9pbnQgaWdub3JlZCBiZWNhdXNlIGl0IG5vIGxvbmdlciBleGlzdHM6ICR7c2F2ZVBvaW50TmFtZX1gKVxuICAgICAgICByZXR1cm5cbiAgICAgIH1cblxuICAgICAgdGhyb3cgZXJyb3JcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUnVucyByb2xsYmFjayBzYXZlIHBvaW50LlxuICAgKiBAcGFyYW0ge3N0cmluZ30gc2F2ZVBvaW50TmFtZSAtIFNhdmUgcG9pbnQgbmFtZS5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgd2hlbiBjb21wbGV0ZS5cbiAgICovXG4gIGFzeW5jIHJvbGxiYWNrU2F2ZVBvaW50KHNhdmVQb2ludE5hbWUpIHtcbiAgICBhd2FpdCB0aGlzLl90cmFuc2FjdGlvbnNBY3Rpb25zTXV0ZXguc3luYyhhc3luYyAoKSA9PiB7XG4gICAgICBhd2FpdCB0aGlzLl9yb2xsYmFja1NhdmVQb2ludEFjdGlvbihzYXZlUG9pbnROYW1lKVxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogUnVucyByb2xsYmFjayBzYXZlIHBvaW50IGFjdGlvbi5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHNhdmVQb2ludE5hbWUgLSBTYXZlIHBvaW50IG5hbWUuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIHdoZW4gY29tcGxldGUuXG4gICAqL1xuICBhc3luYyBfcm9sbGJhY2tTYXZlUG9pbnRBY3Rpb24oc2F2ZVBvaW50TmFtZSkge1xuICAgIGF3YWl0IHRoaXMucXVlcnkoYFJPTExCQUNLIFRPIFNBVkVQT0lOVCAke3NhdmVQb2ludE5hbWV9YClcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHRydW5jYXRlIGFsbCB0YWJsZXMuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIHdoZW4gY29tcGxldGUuXG4gICAqL1xuICBhc3luYyB0cnVuY2F0ZUFsbFRhYmxlcygpIHtcbiAgICB0aGlzLl9hc3NlcnROb3RSZWFkT25seSgpXG4gICAgYXdhaXQgdGhpcy53aXRoRGlzYWJsZWRGb3JlaWduS2V5cyhhc3luYyAoKSA9PiB7XG4gICAgICBsZXQgdHJpZXMgPSAwXG5cbiAgICAgIHdoaWxlKHRyaWVzIDw9IDUpIHtcbiAgICAgICAgdHJpZXMrK1xuXG4gICAgICAgIGNvbnN0IHRhYmxlcyA9IGF3YWl0IHRoaXMuZ2V0VGFibGVzKClcbiAgICAgICAgY29uc3QgdHJ1bmNhdGVFcnJvcnMgPSBbXVxuXG4gICAgICAgIGZvciAoY29uc3QgdGFibGUgb2YgdGFibGVzKSB7XG4gICAgICAgICAgaWYgKHRhYmxlLmdldE5hbWUoKSAhPSBcInNjaGVtYV9taWdyYXRpb25zXCIpIHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgIGF3YWl0IHRhYmxlLnRydW5jYXRlKHtjYXNjYWRlOiB0cnVlfSlcbiAgICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpXG4gICAgICAgICAgICAgIHRydW5jYXRlRXJyb3JzLnB1c2goZXJyb3IpXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRydW5jYXRlRXJyb3JzLmxlbmd0aCA9PSAwKSB7XG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgfSBlbHNlIGlmICh0cmllcyA8PSA1KSB7XG4gICAgICAgICAgLy8gQSB0cnVuY2F0ZSBmYWlsZWQg4oCUIHRoZSBzY2hlbWEgY2FjaGUgbWF5IHN0aWxsIGxpc3QgYSB0YWJsZSB0aGF0IHdhc1xuICAgICAgICAgIC8vIGRyb3BwZWQgb3V0IGZyb20gdW5kZXIgdXMgKGUuZy4gYSBkYjpyb2xsYmFjayB0ZXN0IHRoYXQgbGVmdCB0aGVcbiAgICAgICAgICAvLyBzaGFyZWQgREIgcm9sbGVkIGJhY2spLiBDbGVhciBpdCBzbyB0aGUgbmV4dCBwYXNzIHJlLXJlYWRzIHRoZSBsaXZlXG4gICAgICAgICAgLy8gdGFibGUgbGlzdCBhbmQgbm8gbG9uZ2VyIHRyaWVzIHRvIHRydW5jYXRlIGEgdGFibGUgdGhhdCBpcyBnb25lLlxuICAgICAgICAgIHRoaXMuY2xlYXJTY2hlbWFDYWNoZSgpXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhyb3cgdHJ1bmNhdGVFcnJvcnNbMF1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogUnVucyB1cGRhdGUuXG4gICAqIEBwYXJhbSB7VXBkYXRlU3FsQXJnc1R5cGV9IGFyZ3MgLSBPcHRpb25zIG9iamVjdC5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgd2hlbiBjb21wbGV0ZS5cbiAgICovXG4gIGFzeW5jIHVwZGF0ZShhcmdzKSB7XG4gICAgdGhpcy5fYXNzZXJ0Tm90UmVhZE9ubHkoKVxuICAgIGNvbnN0IHNxbCA9IHRoaXMudXBkYXRlU3FsKGFyZ3MpXG5cbiAgICBhd2FpdCB0aGlzLnF1ZXJ5KHNxbClcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHVwZGF0ZSBzcWwuXG4gICAqIEBhYnN0cmFjdFxuICAgKiBAcGFyYW0ge1VwZGF0ZVNxbEFyZ3NUeXBlfSBhcmdzIC0gT3B0aW9ucyBvYmplY3QuXG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IC0gU1FMIHN0cmluZy5cbiAgICovXG4gIHVwZGF0ZVNxbChhcmdzKSB7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tdW51c2VkLXZhcnNcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCInZGlzYWJsZUZvcmVpZ25LZXlzJyBub3QgaW1wbGVtZW50ZWRcIilcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHVwc2VydCBzcWwuXG4gICAqIEBhYnN0cmFjdFxuICAgKiBAcGFyYW0ge1Vwc2VydFNxbEFyZ3NUeXBlfSBhcmdzIC0gT3B0aW9ucyBvYmplY3QuXG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IC0gU1FMIHN0cmluZy5cbiAgICovXG4gIHVwc2VydFNxbChhcmdzKSB7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tdW51c2VkLXZhcnNcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCIndXBzZXJ0U3FsJyBub3QgaW1wbGVtZW50ZWRcIilcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGRpc2FibGUgZm9yZWlnbiBrZXlzLlxuICAgKiBAYWJzdHJhY3RcbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgd2hlbiBjb21wbGV0ZS5cbiAgICovXG4gIGRpc2FibGVGb3JlaWduS2V5cygpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCInZGlzYWJsZUZvcmVpZ25LZXlzJyBub3QgaW1wbGVtZW50ZWRcIilcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGVuYWJsZSBmb3JlaWduIGtleXMuXG4gICAqIEBhYnN0cmFjdFxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBSZXNvbHZlcyB3aGVuIGNvbXBsZXRlLlxuICAgKi9cbiAgZW5hYmxlRm9yZWlnbktleXMoKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFwiJ2VuYWJsZUZvcmVpZ25LZXlzJyBub3QgaW1wbGVtZW50ZWRcIilcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHdpdGggZGlzYWJsZWQgZm9yZWlnbiBrZXlzLlxuICAgKiBAcGFyYW0ge2Z1bmN0aW9uKCkgOiB2b2lkfSBjYWxsYmFjayAtIENhbGxiYWNrIGZ1bmN0aW9uLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTw/Pn0gLSBSZXNvbHZlcyB3aXRoIHRoZSB3aXRoIGRpc2FibGVkIGZvcmVpZ24ga2V5cy5cbiAgICovXG4gIGFzeW5jIHdpdGhEaXNhYmxlZEZvcmVpZ25LZXlzKGNhbGxiYWNrKSB7XG4gICAgYXdhaXQgdGhpcy5kaXNhYmxlRm9yZWlnbktleXMoKVxuXG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBhd2FpdCBjYWxsYmFjaygpXG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIGF3YWl0IHRoaXMuZW5hYmxlRm9yZWlnbktleXMoKVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBCbG9ja3MgdW50aWwgYSBuYW1lZCBhZHZpc29yeSBsb2NrIGlzIGFjcXVpcmVkIG9uIHRoaXMgY29ubmVjdGlvbi5cbiAgICogQWR2aXNvcnkgbG9ja3MgYXJlIGNvbm5lY3Rpb24tc2NvcGVkIGFuZCBkbyBub3QgaW50ZXJhY3Qgd2l0aCByb3cgb3JcbiAgICogdGFibGUgbG9ja3M7IHRoZXkgYXJlIHB1cmVseSBjb29wZXJhdGl2ZSBiZXR3ZWVuIGNhbGxlcnMgdGhhdCB1c2UgdGhlXG4gICAqIHNhbWUgbmFtZSBhbmQgbGV0IHlvdSBzZXJpYWxpemUgZnVuY3Rpb25hbGl0eSB3aXRob3V0IGJsb2NraW5nIHJlYWRlcnNcbiAgICogb3Igd3JpdGVycyB0aGF0IGRvIG5vdCBwYXJ0aWNpcGF0ZSBpbiB0aGUgc2FtZSBsb2NrLlxuICAgKiBAYWJzdHJhY3RcbiAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgLSBMb2NrIG5hbWUuXG4gICAqIEBwYXJhbSB7e3RpbWVvdXRNcz86IG51bWJlciB8IG51bGx9fSBbX2FyZ3NdIC0gT3B0aW9uYWwgdGltZW91dCBpbiBtaWxsaXNlY29uZHM7IGBudWxsYCBvciB1bmRlZmluZWQgYmxvY2tzIGZvcmV2ZXIuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSAtIFJlc29sdmVzIHRvIHRydWUgd2hlbiB0aGUgbG9jayBoYXMgYmVlbiBhY3F1aXJlZCwgZmFsc2UgaWYgdGhlIHRpbWVvdXQgZWxhcHNlZC5cbiAgICovXG4gIGFjcXVpcmVBZHZpc29yeUxvY2sobmFtZSwgX2FyZ3MgPSB7fSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgJ2FjcXVpcmVBZHZpc29yeUxvY2snIG5vdCBpbXBsZW1lbnRlZCBmb3IgJHt0aGlzLmNvbnN0cnVjdG9yLm5hbWV9YClcbiAgfVxuXG4gIC8qKlxuICAgKiBBdHRlbXB0cyB0byBhY3F1aXJlIGEgbmFtZWQgYWR2aXNvcnkgbG9jayB3aXRob3V0IGJsb2NraW5nLlxuICAgKiBAYWJzdHJhY3RcbiAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgLSBMb2NrIG5hbWUuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSAtIFJlc29sdmVzIHRvIHRydWUgaWYgdGhlIGxvY2sgd2FzIGFjcXVpcmVkLCBmYWxzZSBpZiBpdCB3YXMgYWxyZWFkeSBoZWxkLlxuICAgKi9cbiAgdHJ5QWNxdWlyZUFkdmlzb3J5TG9jayhuYW1lKSB7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tdW51c2VkLXZhcnNcbiAgICB0aHJvdyBuZXcgRXJyb3IoYCd0cnlBY3F1aXJlQWR2aXNvcnlMb2NrJyBub3QgaW1wbGVtZW50ZWQgZm9yICR7dGhpcy5jb25zdHJ1Y3Rvci5uYW1lfWApXG4gIH1cblxuICAvKipcbiAgICogUmVsZWFzZXMgYSBuYW1lZCBhZHZpc29yeSBsb2NrIHByZXZpb3VzbHkgYWNxdWlyZWQgb24gdGhpcyBjb25uZWN0aW9uLlxuICAgKiBAYWJzdHJhY3RcbiAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgLSBMb2NrIG5hbWUuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSAtIFJlc29sdmVzIHRvIHRydWUgaWYgdGhlIGxvY2sgd2FzIGhlbGQgYnkgdGhpcyBzZXNzaW9uIGFuZCBoYXMgbm93IGJlZW4gcmVsZWFzZWQuXG4gICAqL1xuICByZWxlYXNlQWR2aXNvcnlMb2NrKG5hbWUpIHsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby11bnVzZWQtdmFyc1xuICAgIHRocm93IG5ldyBFcnJvcihgJ3JlbGVhc2VBZHZpc29yeUxvY2snIG5vdCBpbXBsZW1lbnRlZCBmb3IgJHt0aGlzLmNvbnN0cnVjdG9yLm5hbWV9YClcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVja3Mgd2hldGhlciBhIG5hbWVkIGFkdmlzb3J5IGxvY2sgaXMgY3VycmVudGx5IGhlbGQgYnkgYW55IHNlc3Npb24uXG4gICAqIEludGVuZGVkIGFzIGFuIGludHJvc3BlY3Rpb24gaGVscGVyOyBjYWxsZXJzIHdobyBuZWVkIHRvIGFjdCBvbiB0aGVcbiAgICogcmVzdWx0IHNob3VsZCBwcmVmZXIgYHRyeUFjcXVpcmVBZHZpc29yeUxvY2tgIHRvIGF2b2lkIGEgVE9DVE9VIHJhY2UuXG4gICAqIEBhYnN0cmFjdFxuICAgKiBAcGFyYW0ge3N0cmluZ30gbmFtZSAtIExvY2sgbmFtZS5cbiAgICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IC0gUmVzb2x2ZXMgdG8gdHJ1ZSBpZiB0aGUgbG9jayBpcyBoZWxkIGJ5ID8gc2Vzc2lvbi5cbiAgICovXG4gIGlzQWR2aXNvcnlMb2NrSGVsZChuYW1lKSB7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tdW51c2VkLXZhcnNcbiAgICB0aHJvdyBuZXcgRXJyb3IoYCdpc0Fkdmlzb3J5TG9ja0hlbGQnIG5vdCBpbXBsZW1lbnRlZCBmb3IgJHt0aGlzLmNvbnN0cnVjdG9yLm5hbWV9YClcbiAgfVxufVxuIl19