@spooky-sync/core 0.0.1-canary.24 → 0.0.1-canary.240

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 (303) hide show
  1. package/AGENTS.md +58 -0
  2. package/coverage/lcov-report/base.css +224 -0
  3. package/coverage/lcov-report/block-navigation.js +87 -0
  4. package/coverage/lcov-report/favicon.png +0 -0
  5. package/coverage/lcov-report/index.html +476 -0
  6. package/coverage/lcov-report/prettify.css +1 -0
  7. package/coverage/lcov-report/prettify.js +2 -0
  8. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  9. package/coverage/lcov-report/sorter.js +210 -0
  10. package/coverage/lcov-report/src/boot/auth-flip.saga.ts.html +271 -0
  11. package/coverage/lcov-report/src/boot/boot.saga.ts.html +469 -0
  12. package/coverage/lcov-report/src/boot/bucket-switch.saga.ts.html +430 -0
  13. package/coverage/lcov-report/src/boot/index.html +161 -0
  14. package/coverage/lcov-report/src/boot/preload.saga.ts.html +178 -0
  15. package/coverage/lcov-report/src/client/bucket-handle.ts.html +766 -0
  16. package/coverage/lcov-report/src/client/index.html +161 -0
  17. package/coverage/lcov-report/src/client/router.ts.html +367 -0
  18. package/coverage/lcov-report/src/client/runtime.ts.html +940 -0
  19. package/coverage/lcov-report/src/client/sp00ky-client.ts.html +1531 -0
  20. package/coverage/lcov-report/src/events/index.html +116 -0
  21. package/coverage/lcov-report/src/events/index.ts.html +877 -0
  22. package/coverage/lcov-report/src/index.html +146 -0
  23. package/coverage/lcov-report/src/index.ts.html +202 -0
  24. package/coverage/lcov-report/src/kernel/constants.ts.html +247 -0
  25. package/coverage/lcov-report/src/kernel/effects.ts.html +562 -0
  26. package/coverage/lcov-report/src/kernel/events.ts.html +250 -0
  27. package/coverage/lcov-report/src/kernel/index.html +176 -0
  28. package/coverage/lcov-report/src/kernel/interpreter.ts.html +514 -0
  29. package/coverage/lcov-report/src/kernel/saga.ts.html +304 -0
  30. package/coverage/lcov-report/src/modules/app-release/index.html +116 -0
  31. package/coverage/lcov-report/src/modules/app-release/index.ts.html +712 -0
  32. package/coverage/lcov-report/src/modules/auth/events/index.html +116 -0
  33. package/coverage/lcov-report/src/modules/auth/events/index.ts.html +142 -0
  34. package/coverage/lcov-report/src/modules/auth/index.html +116 -0
  35. package/coverage/lcov-report/src/modules/auth/index.ts.html +1225 -0
  36. package/coverage/lcov-report/src/modules/crdt/crdt-field.ts.html +967 -0
  37. package/coverage/lcov-report/src/modules/crdt/index.html +146 -0
  38. package/coverage/lcov-report/src/modules/crdt/index.ts.html +1474 -0
  39. package/coverage/lcov-report/src/modules/crdt/loro-loader.ts.html +160 -0
  40. package/coverage/lcov-report/src/modules/devtools/flags.ts.html +1132 -0
  41. package/coverage/lcov-report/src/modules/devtools/index.html +161 -0
  42. package/coverage/lcov-report/src/modules/devtools/index.ts.html +2413 -0
  43. package/coverage/lcov-report/src/modules/devtools/storage-info.ts.html +589 -0
  44. package/coverage/lcov-report/src/modules/devtools/versions.ts.html +415 -0
  45. package/coverage/lcov-report/src/modules/feature-flag/index.html +116 -0
  46. package/coverage/lcov-report/src/modules/feature-flag/index.ts.html +1033 -0
  47. package/coverage/lcov-report/src/modules/index.html +116 -0
  48. package/coverage/lcov-report/src/modules/ref-tables.ts.html +349 -0
  49. package/coverage/lcov-report/src/mutation/index.html +191 -0
  50. package/coverage/lcov-report/src/mutation/jobs.ts.html +208 -0
  51. package/coverage/lcov-report/src/mutation/mutation-id.ts.html +190 -0
  52. package/coverage/lcov-report/src/mutation/push.saga.ts.html +730 -0
  53. package/coverage/lcov-report/src/mutation/rows.ts.html +1216 -0
  54. package/coverage/lcov-report/src/mutation/tray.saga.ts.html +229 -0
  55. package/coverage/lcov-report/src/mutation/write.saga.ts.html +583 -0
  56. package/coverage/lcov-report/src/otel/index.html +116 -0
  57. package/coverage/lcov-report/src/otel/index.ts.html +466 -0
  58. package/coverage/lcov-report/src/query/env.ts.html +253 -0
  59. package/coverage/lcov-report/src/query/fetch.saga.ts.html +412 -0
  60. package/coverage/lcov-report/src/query/hash.ts.html +139 -0
  61. package/coverage/lcov-report/src/query/index.html +281 -0
  62. package/coverage/lcov-report/src/query/lifecycle.saga.ts.html +388 -0
  63. package/coverage/lcov-report/src/query/materialize.saga.ts.html +310 -0
  64. package/coverage/lcov-report/src/query/materialize.ts.html +217 -0
  65. package/coverage/lcov-report/src/query/membership.saga.ts.html +709 -0
  66. package/coverage/lcov-report/src/query/membership.ts.html +559 -0
  67. package/coverage/lcov-report/src/query/register.saga.ts.html +655 -0
  68. package/coverage/lcov-report/src/query/render-set.ts.html +265 -0
  69. package/coverage/lcov-report/src/query/sql.ts.html +322 -0
  70. package/coverage/lcov-report/src/query/window-query.ts.html +670 -0
  71. package/coverage/lcov-report/src/services/blobs/blob-cache.ts.html +1894 -0
  72. package/coverage/lcov-report/src/services/blobs/blob-manifest.ts.html +766 -0
  73. package/coverage/lcov-report/src/services/blobs/blob-store.ts.html +1162 -0
  74. package/coverage/lcov-report/src/services/blobs/index.html +161 -0
  75. package/coverage/lcov-report/src/services/blobs/index.ts.html +295 -0
  76. package/coverage/lcov-report/src/services/database/cache-engine.ts.html +664 -0
  77. package/coverage/lcov-report/src/services/database/connection-supervisor.ts.html +1330 -0
  78. package/coverage/lcov-report/src/services/database/database.ts.html +658 -0
  79. package/coverage/lcov-report/src/services/database/engine-factory.ts.html +184 -0
  80. package/coverage/lcov-report/src/services/database/errors.ts.html +187 -0
  81. package/coverage/lcov-report/src/services/database/events/index.html +116 -0
  82. package/coverage/lcov-report/src/services/database/events/index.ts.html +184 -0
  83. package/coverage/lcov-report/src/services/database/index.html +386 -0
  84. package/coverage/lcov-report/src/services/database/index.ts.html +121 -0
  85. package/coverage/lcov-report/src/services/database/local-migrator.ts.html +703 -0
  86. package/coverage/lcov-report/src/services/database/local.ts.html +1633 -0
  87. package/coverage/lcov-report/src/services/database/plan-render.ts.html +409 -0
  88. package/coverage/lcov-report/src/services/database/relation-resolver.ts.html +682 -0
  89. package/coverage/lcov-report/src/services/database/remote.ts.html +1036 -0
  90. package/coverage/lcov-report/src/services/database/sqlite-cache-engine.ts.html +4132 -0
  91. package/coverage/lcov-report/src/services/database/sqlite-lock-verify.ts.html +220 -0
  92. package/coverage/lcov-report/src/services/database/sqlite-open.ts.html +577 -0
  93. package/coverage/lcov-report/src/services/database/sqlite-plan-sql.ts.html +499 -0
  94. package/coverage/lcov-report/src/services/database/sqlite-select.ts.html +478 -0
  95. package/coverage/lcov-report/src/services/database/sqlite-transport.ts.html +757 -0
  96. package/coverage/lcov-report/src/services/database/surql-translate.ts.html +1333 -0
  97. package/coverage/lcov-report/src/services/database/surreal-cache-engine.ts.html +568 -0
  98. package/coverage/lcov-report/src/services/logger/index.html +116 -0
  99. package/coverage/lcov-report/src/services/logger/index.ts.html +154 -0
  100. package/coverage/lcov-report/src/services/persistence/index.html +146 -0
  101. package/coverage/lcov-report/src/services/persistence/localstorage.ts.html +163 -0
  102. package/coverage/lcov-report/src/services/persistence/resilient.ts.html +208 -0
  103. package/coverage/lcov-report/src/services/persistence/surrealdb.ts.html +271 -0
  104. package/coverage/lcov-report/src/services/stream-processor/index.html +146 -0
  105. package/coverage/lcov-report/src/services/stream-processor/index.ts.html +3313 -0
  106. package/coverage/lcov-report/src/services/stream-processor/permissions.ts.html +244 -0
  107. package/coverage/lcov-report/src/services/stream-processor/wasm-types.ts.html +346 -0
  108. package/coverage/lcov-report/src/services/tabs/broker-client.ts.html +934 -0
  109. package/coverage/lcov-report/src/services/tabs/coordinator.ts.html +1984 -0
  110. package/coverage/lcov-report/src/services/tabs/index.html +191 -0
  111. package/coverage/lcov-report/src/services/tabs/leader-locks.ts.html +310 -0
  112. package/coverage/lcov-report/src/services/tabs/protocol.ts.html +871 -0
  113. package/coverage/lcov-report/src/services/tabs/support.ts.html +193 -0
  114. package/coverage/lcov-report/src/services/tabs/tabs-broker-worker.ts.html +2005 -0
  115. package/coverage/lcov-report/src/sp00ky.ts.html +100 -0
  116. package/coverage/lcov-report/src/state/client-state.ts.html +637 -0
  117. package/coverage/lcov-report/src/state/index.html +161 -0
  118. package/coverage/lcov-report/src/state/lifecycle.ts.html +343 -0
  119. package/coverage/lcov-report/src/state/reducers.ts.html +1471 -0
  120. package/coverage/lcov-report/src/state/selectors.ts.html +637 -0
  121. package/coverage/lcov-report/src/sync/connection.saga.ts.html +343 -0
  122. package/coverage/lcov-report/src/sync/index.html +176 -0
  123. package/coverage/lcov-report/src/sync/live.saga.ts.html +232 -0
  124. package/coverage/lcov-report/src/sync/policy.ts.html +1606 -0
  125. package/coverage/lcov-report/src/sync/poll.saga.ts.html +193 -0
  126. package/coverage/lcov-report/src/sync/tabs.saga.ts.html +361 -0
  127. package/coverage/lcov-report/src/types.ts.html +2419 -0
  128. package/coverage/lcov-report/src/utils/blurhash.ts.html +355 -0
  129. package/coverage/lcov-report/src/utils/error-classification.ts.html +244 -0
  130. package/coverage/lcov-report/src/utils/index.html +191 -0
  131. package/coverage/lcov-report/src/utils/index.ts.html +820 -0
  132. package/coverage/lcov-report/src/utils/parser.ts.html +313 -0
  133. package/coverage/lcov-report/src/utils/semver.ts.html +175 -0
  134. package/coverage/lcov-report/src/utils/surql.ts.html +667 -0
  135. package/coverage/lcov.info +19079 -0
  136. package/dist/index.d.ts +2946 -140
  137. package/dist/index.js +13424 -2356
  138. package/dist/otel/index.d.ts +2 -2
  139. package/dist/otel/index.js +6 -6
  140. package/dist/sqlite-open.js +322 -0
  141. package/dist/sqlite-worker.d.ts +1 -0
  142. package/dist/sqlite-worker.js +439 -0
  143. package/dist/tabs-broker-worker.d.ts +8 -0
  144. package/dist/tabs-broker-worker.js +472 -0
  145. package/dist/types.d.ts +769 -11
  146. package/package.json +11 -7
  147. package/scripts/check-broker-bundle.mjs +33 -0
  148. package/skills/{spooky-core → sp00ky-core}/SKILL.md +12 -12
  149. package/skills/{spooky-core → sp00ky-core}/references/auth.md +1 -1
  150. package/skills/{spooky-core → sp00ky-core}/references/config.md +2 -2
  151. package/src/bucket-blurhash.test.ts +148 -0
  152. package/src/build-globals.d.ts +12 -0
  153. package/src/events/events.test.ts +2 -1
  154. package/src/events/index.ts +3 -0
  155. package/src/index.ts +36 -2
  156. package/src/modules/app-release/index.test.ts +125 -0
  157. package/src/modules/app-release/index.ts +201 -0
  158. package/src/modules/auth/auth.local-first.test.ts +141 -0
  159. package/src/modules/auth/events/index.ts +2 -1
  160. package/src/modules/auth/index.ts +138 -25
  161. package/src/modules/cache/cache.relay.test.ts +95 -0
  162. package/src/modules/cache/index.ts +163 -43
  163. package/src/modules/cache/types.ts +2 -2
  164. package/src/modules/crdt/crdt-field.ts +294 -0
  165. package/src/modules/crdt/crdt-hydration.test.ts +210 -0
  166. package/src/modules/crdt/crdt-reconnect.test.ts +195 -0
  167. package/src/modules/crdt/index.ts +463 -0
  168. package/src/modules/crdt/loro-loader.ts +25 -0
  169. package/src/modules/data/data.activity.test.ts +109 -0
  170. package/src/modules/data/data.authority.test.ts +122 -0
  171. package/src/modules/data/data.heartbeat-wake.test.ts +115 -0
  172. package/src/modules/data/data.hydration.test.ts +142 -0
  173. package/src/modules/data/data.membership.test.ts +623 -0
  174. package/src/modules/data/data.notify-table.test.ts +41 -0
  175. package/src/modules/data/data.pending-ids.test.ts +199 -0
  176. package/src/modules/data/data.rebind.test.ts +170 -0
  177. package/src/modules/data/data.rematerialize.test.ts +114 -0
  178. package/src/modules/data/data.run.test.ts +113 -0
  179. package/src/modules/data/data.settled-writes.test.ts +235 -0
  180. package/src/modules/data/data.status.test.ts +249 -0
  181. package/src/modules/data/id-set-plan.test.ts +122 -0
  182. package/src/modules/data/index.ts +2031 -150
  183. package/src/modules/data/mutation-id.test.ts +25 -0
  184. package/src/modules/data/mutation-id.ts +35 -0
  185. package/src/modules/data/window-query.test.ts +52 -0
  186. package/src/modules/data/window-query.ts +194 -0
  187. package/src/modules/devtools/flags.ts +349 -0
  188. package/src/modules/devtools/index.ts +451 -46
  189. package/src/modules/devtools/notify-throttle.test.ts +154 -0
  190. package/src/modules/devtools/state-shape.test.ts +146 -0
  191. package/src/modules/devtools/storage-info.test.ts +79 -0
  192. package/src/modules/devtools/storage-info.ts +168 -0
  193. package/src/modules/devtools/versions.test.ts +74 -0
  194. package/src/modules/devtools/versions.ts +110 -0
  195. package/src/modules/feature-flag/index.test.ts +251 -0
  196. package/src/modules/feature-flag/index.ts +308 -0
  197. package/src/modules/ref-tables.test.ts +91 -0
  198. package/src/modules/ref-tables.ts +88 -0
  199. package/src/modules/sync/engine.ts +170 -86
  200. package/src/modules/sync/events/index.ts +9 -2
  201. package/src/modules/sync/queue/queue-down.test.ts +228 -0
  202. package/src/modules/sync/queue/queue-down.ts +108 -13
  203. package/src/modules/sync/queue/queue-up.forwarded.test.ts +164 -0
  204. package/src/modules/sync/queue/queue-up.ts +241 -57
  205. package/src/modules/sync/scheduler.pause.test.ts +109 -0
  206. package/src/modules/sync/scheduler.retry.test.ts +237 -0
  207. package/src/modules/sync/scheduler.ts +215 -13
  208. package/src/modules/sync/sync.cleanup.test.ts +116 -0
  209. package/src/modules/sync/sync.health.test.ts +167 -0
  210. package/src/modules/sync/sync.heartbeat.test.ts +80 -0
  211. package/src/modules/sync/sync.list-ref-meta.test.ts +193 -0
  212. package/src/modules/sync/sync.live-removal.test.ts +289 -0
  213. package/src/modules/sync/sync.reconnect.test.ts +145 -0
  214. package/src/modules/sync/sync.rematerialize-after-fetch.test.ts +93 -0
  215. package/src/modules/sync/sync.settled-poll.test.ts +58 -0
  216. package/src/modules/sync/sync.subquery.test.ts +82 -0
  217. package/src/modules/sync/sync.tabs.test.ts +249 -0
  218. package/src/modules/sync/sync.ts +2350 -133
  219. package/src/modules/sync/utils.test.ts +322 -2
  220. package/src/modules/sync/utils.ts +286 -16
  221. package/src/otel/index.ts +13 -10
  222. package/src/services/blobs/blob-cache.test.ts +359 -0
  223. package/src/services/blobs/blob-cache.ts +603 -0
  224. package/src/services/blobs/blob-manifest.ts +227 -0
  225. package/src/services/blobs/blob-store.test.ts +77 -0
  226. package/src/services/blobs/blob-store.ts +359 -0
  227. package/src/services/blobs/blob.fixture.ts +90 -0
  228. package/src/services/blobs/index.ts +70 -0
  229. package/src/services/database/cache-engine.ts +193 -0
  230. package/src/services/database/connection-supervisor.test.ts +289 -0
  231. package/src/services/database/connection-supervisor.ts +415 -0
  232. package/src/services/database/database.query-timeout.test.ts +140 -0
  233. package/src/services/database/database.ts +130 -62
  234. package/src/services/database/engine-factory.ts +33 -0
  235. package/src/services/database/errors.ts +34 -0
  236. package/src/services/database/events/index.ts +2 -1
  237. package/src/services/database/index.ts +7 -0
  238. package/src/services/database/local-migrator.ts +30 -27
  239. package/src/services/database/local.test.ts +64 -0
  240. package/src/services/database/local.ts +484 -67
  241. package/src/services/database/plan-render.test.ts +159 -0
  242. package/src/services/database/plan-render.ts +108 -0
  243. package/src/services/database/relation-resolver.test.ts +467 -0
  244. package/src/services/database/relation-resolver.ts +0 -0
  245. package/src/services/database/remote.ts +222 -15
  246. package/src/services/database/sqlite-cache-engine.test.ts +616 -0
  247. package/src/services/database/sqlite-cache-engine.timeout.test.ts +61 -0
  248. package/src/services/database/sqlite-cache-engine.ts +1358 -0
  249. package/src/services/database/sqlite-devtools-queries.integration.test.ts +143 -0
  250. package/src/services/database/sqlite-devtools-queries.test.ts +154 -0
  251. package/src/services/database/sqlite-lock-verify.test.ts +33 -0
  252. package/src/services/database/sqlite-lock-verify.ts +45 -0
  253. package/src/services/database/sqlite-open.test.ts +150 -0
  254. package/src/services/database/sqlite-open.ts +164 -0
  255. package/src/services/database/sqlite-plan-sql.test.ts +104 -0
  256. package/src/services/database/sqlite-plan-sql.ts +138 -0
  257. package/src/services/database/sqlite-projection.test.ts +99 -0
  258. package/src/services/database/sqlite-select.integration.test.ts +185 -0
  259. package/src/services/database/sqlite-select.test.ts +246 -0
  260. package/src/services/database/sqlite-select.ts +131 -0
  261. package/src/services/database/sqlite-transport.fixture.ts +30 -0
  262. package/src/services/database/sqlite-transport.ts +224 -0
  263. package/src/services/database/sqlite-worker.ts +437 -0
  264. package/src/services/database/surql-translate.ts +416 -0
  265. package/src/services/database/surreal-cache-engine.ts +161 -0
  266. package/src/services/logger/index.ts +3 -2
  267. package/src/services/persistence/localstorage.ts +2 -2
  268. package/src/services/persistence/resilient.ts +11 -4
  269. package/src/services/persistence/surrealdb.ts +10 -10
  270. package/src/services/stream-processor/index.ts +796 -84
  271. package/src/services/stream-processor/permissions.test.ts +47 -0
  272. package/src/services/stream-processor/permissions.ts +53 -0
  273. package/src/services/stream-processor/stream-processor.batch.test.ts +186 -0
  274. package/src/services/stream-processor/stream-processor.prime.test.ts +198 -0
  275. package/src/services/stream-processor/stream-processor.reset.test.ts +226 -0
  276. package/src/services/stream-processor/stream-processor.test.ts +1 -1
  277. package/src/services/stream-processor/wasm-types.ts +59 -3
  278. package/src/services/tabs/broker-client.ts +283 -0
  279. package/src/services/tabs/broker.test.ts +327 -0
  280. package/src/services/tabs/coordinator.test.ts +365 -0
  281. package/src/services/tabs/coordinator.ts +633 -0
  282. package/src/services/tabs/fake-ports.fixture.ts +112 -0
  283. package/src/services/tabs/leader-locks.ts +75 -0
  284. package/src/services/tabs/protocol.ts +258 -0
  285. package/src/services/tabs/support.ts +36 -0
  286. package/src/services/tabs/tabs-broker-worker.ts +640 -0
  287. package/src/sp00ky.auth-order.test.ts +112 -0
  288. package/src/sp00ky.init-query.test.ts +183 -0
  289. package/src/sp00ky.local-first.test.ts +60 -0
  290. package/src/sp00ky.ts +1854 -0
  291. package/src/types.ts +548 -13
  292. package/src/utils/blurhash.ts +90 -0
  293. package/src/utils/error-classification.test.ts +54 -0
  294. package/src/utils/error-classification.ts +25 -0
  295. package/src/utils/index.ts +79 -13
  296. package/src/utils/parser.test.ts +49 -120
  297. package/src/utils/parser.ts +32 -2
  298. package/src/utils/semver.test.ts +32 -0
  299. package/src/utils/semver.ts +30 -0
  300. package/src/utils/surql.ts +30 -18
  301. package/src/utils/withRetry.test.ts +1 -1
  302. package/tsdown.config.ts +86 -1
  303. package/src/spooky.ts +0 -395
@@ -0,0 +1,1333 @@
1
+
2
+ <!doctype html>
3
+ <html lang="en">
4
+
5
+ <head>
6
+ <title>Code coverage report for src/services/database/surql-translate.ts</title>
7
+ <meta charset="utf-8" />
8
+ <link rel="stylesheet" href="../../../prettify.css" />
9
+ <link rel="stylesheet" href="../../../base.css" />
10
+ <link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" />
11
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
12
+ <style type='text/css'>
13
+ .coverage-summary .sorter {
14
+ background-image: url(../../../sort-arrow-sprite.png);
15
+ }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <div class='wrapper'>
21
+ <div class='pad1'>
22
+ <h1><a href="../../../index.html">All files</a> / <a href="index.html">src/services/database</a> surql-translate.ts</h1>
23
+ <div class='clearfix'>
24
+
25
+ <div class='fl pad1y space-right2'>
26
+ <span class="strong">79.67% </span>
27
+ <span class="quiet">Statements</span>
28
+ <span class='fraction'>196/246</span>
29
+ </div>
30
+
31
+
32
+ <div class='fl pad1y space-right2'>
33
+ <span class="strong">74.33% </span>
34
+ <span class="quiet">Branches</span>
35
+ <span class='fraction'>84/113</span>
36
+ </div>
37
+
38
+
39
+ <div class='fl pad1y space-right2'>
40
+ <span class="strong">95% </span>
41
+ <span class="quiet">Functions</span>
42
+ <span class='fraction'>19/20</span>
43
+ </div>
44
+
45
+
46
+ <div class='fl pad1y space-right2'>
47
+ <span class="strong">79.67% </span>
48
+ <span class="quiet">Lines</span>
49
+ <span class='fraction'>196/246</span>
50
+ </div>
51
+
52
+
53
+ </div>
54
+ <p class="quiet">
55
+ Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block.
56
+ </p>
57
+ <template id="filterTemplate">
58
+ <div class="quiet">
59
+ Filter:
60
+ <input type="search" id="fileSearch">
61
+ </div>
62
+ </template>
63
+ </div>
64
+ <div class='status-line medium'></div>
65
+ <pre><table class="coverage">
66
+ <tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
67
+ <a name='L2'></a><a href='#L2'>2</a>
68
+ <a name='L3'></a><a href='#L3'>3</a>
69
+ <a name='L4'></a><a href='#L4'>4</a>
70
+ <a name='L5'></a><a href='#L5'>5</a>
71
+ <a name='L6'></a><a href='#L6'>6</a>
72
+ <a name='L7'></a><a href='#L7'>7</a>
73
+ <a name='L8'></a><a href='#L8'>8</a>
74
+ <a name='L9'></a><a href='#L9'>9</a>
75
+ <a name='L10'></a><a href='#L10'>10</a>
76
+ <a name='L11'></a><a href='#L11'>11</a>
77
+ <a name='L12'></a><a href='#L12'>12</a>
78
+ <a name='L13'></a><a href='#L13'>13</a>
79
+ <a name='L14'></a><a href='#L14'>14</a>
80
+ <a name='L15'></a><a href='#L15'>15</a>
81
+ <a name='L16'></a><a href='#L16'>16</a>
82
+ <a name='L17'></a><a href='#L17'>17</a>
83
+ <a name='L18'></a><a href='#L18'>18</a>
84
+ <a name='L19'></a><a href='#L19'>19</a>
85
+ <a name='L20'></a><a href='#L20'>20</a>
86
+ <a name='L21'></a><a href='#L21'>21</a>
87
+ <a name='L22'></a><a href='#L22'>22</a>
88
+ <a name='L23'></a><a href='#L23'>23</a>
89
+ <a name='L24'></a><a href='#L24'>24</a>
90
+ <a name='L25'></a><a href='#L25'>25</a>
91
+ <a name='L26'></a><a href='#L26'>26</a>
92
+ <a name='L27'></a><a href='#L27'>27</a>
93
+ <a name='L28'></a><a href='#L28'>28</a>
94
+ <a name='L29'></a><a href='#L29'>29</a>
95
+ <a name='L30'></a><a href='#L30'>30</a>
96
+ <a name='L31'></a><a href='#L31'>31</a>
97
+ <a name='L32'></a><a href='#L32'>32</a>
98
+ <a name='L33'></a><a href='#L33'>33</a>
99
+ <a name='L34'></a><a href='#L34'>34</a>
100
+ <a name='L35'></a><a href='#L35'>35</a>
101
+ <a name='L36'></a><a href='#L36'>36</a>
102
+ <a name='L37'></a><a href='#L37'>37</a>
103
+ <a name='L38'></a><a href='#L38'>38</a>
104
+ <a name='L39'></a><a href='#L39'>39</a>
105
+ <a name='L40'></a><a href='#L40'>40</a>
106
+ <a name='L41'></a><a href='#L41'>41</a>
107
+ <a name='L42'></a><a href='#L42'>42</a>
108
+ <a name='L43'></a><a href='#L43'>43</a>
109
+ <a name='L44'></a><a href='#L44'>44</a>
110
+ <a name='L45'></a><a href='#L45'>45</a>
111
+ <a name='L46'></a><a href='#L46'>46</a>
112
+ <a name='L47'></a><a href='#L47'>47</a>
113
+ <a name='L48'></a><a href='#L48'>48</a>
114
+ <a name='L49'></a><a href='#L49'>49</a>
115
+ <a name='L50'></a><a href='#L50'>50</a>
116
+ <a name='L51'></a><a href='#L51'>51</a>
117
+ <a name='L52'></a><a href='#L52'>52</a>
118
+ <a name='L53'></a><a href='#L53'>53</a>
119
+ <a name='L54'></a><a href='#L54'>54</a>
120
+ <a name='L55'></a><a href='#L55'>55</a>
121
+ <a name='L56'></a><a href='#L56'>56</a>
122
+ <a name='L57'></a><a href='#L57'>57</a>
123
+ <a name='L58'></a><a href='#L58'>58</a>
124
+ <a name='L59'></a><a href='#L59'>59</a>
125
+ <a name='L60'></a><a href='#L60'>60</a>
126
+ <a name='L61'></a><a href='#L61'>61</a>
127
+ <a name='L62'></a><a href='#L62'>62</a>
128
+ <a name='L63'></a><a href='#L63'>63</a>
129
+ <a name='L64'></a><a href='#L64'>64</a>
130
+ <a name='L65'></a><a href='#L65'>65</a>
131
+ <a name='L66'></a><a href='#L66'>66</a>
132
+ <a name='L67'></a><a href='#L67'>67</a>
133
+ <a name='L68'></a><a href='#L68'>68</a>
134
+ <a name='L69'></a><a href='#L69'>69</a>
135
+ <a name='L70'></a><a href='#L70'>70</a>
136
+ <a name='L71'></a><a href='#L71'>71</a>
137
+ <a name='L72'></a><a href='#L72'>72</a>
138
+ <a name='L73'></a><a href='#L73'>73</a>
139
+ <a name='L74'></a><a href='#L74'>74</a>
140
+ <a name='L75'></a><a href='#L75'>75</a>
141
+ <a name='L76'></a><a href='#L76'>76</a>
142
+ <a name='L77'></a><a href='#L77'>77</a>
143
+ <a name='L78'></a><a href='#L78'>78</a>
144
+ <a name='L79'></a><a href='#L79'>79</a>
145
+ <a name='L80'></a><a href='#L80'>80</a>
146
+ <a name='L81'></a><a href='#L81'>81</a>
147
+ <a name='L82'></a><a href='#L82'>82</a>
148
+ <a name='L83'></a><a href='#L83'>83</a>
149
+ <a name='L84'></a><a href='#L84'>84</a>
150
+ <a name='L85'></a><a href='#L85'>85</a>
151
+ <a name='L86'></a><a href='#L86'>86</a>
152
+ <a name='L87'></a><a href='#L87'>87</a>
153
+ <a name='L88'></a><a href='#L88'>88</a>
154
+ <a name='L89'></a><a href='#L89'>89</a>
155
+ <a name='L90'></a><a href='#L90'>90</a>
156
+ <a name='L91'></a><a href='#L91'>91</a>
157
+ <a name='L92'></a><a href='#L92'>92</a>
158
+ <a name='L93'></a><a href='#L93'>93</a>
159
+ <a name='L94'></a><a href='#L94'>94</a>
160
+ <a name='L95'></a><a href='#L95'>95</a>
161
+ <a name='L96'></a><a href='#L96'>96</a>
162
+ <a name='L97'></a><a href='#L97'>97</a>
163
+ <a name='L98'></a><a href='#L98'>98</a>
164
+ <a name='L99'></a><a href='#L99'>99</a>
165
+ <a name='L100'></a><a href='#L100'>100</a>
166
+ <a name='L101'></a><a href='#L101'>101</a>
167
+ <a name='L102'></a><a href='#L102'>102</a>
168
+ <a name='L103'></a><a href='#L103'>103</a>
169
+ <a name='L104'></a><a href='#L104'>104</a>
170
+ <a name='L105'></a><a href='#L105'>105</a>
171
+ <a name='L106'></a><a href='#L106'>106</a>
172
+ <a name='L107'></a><a href='#L107'>107</a>
173
+ <a name='L108'></a><a href='#L108'>108</a>
174
+ <a name='L109'></a><a href='#L109'>109</a>
175
+ <a name='L110'></a><a href='#L110'>110</a>
176
+ <a name='L111'></a><a href='#L111'>111</a>
177
+ <a name='L112'></a><a href='#L112'>112</a>
178
+ <a name='L113'></a><a href='#L113'>113</a>
179
+ <a name='L114'></a><a href='#L114'>114</a>
180
+ <a name='L115'></a><a href='#L115'>115</a>
181
+ <a name='L116'></a><a href='#L116'>116</a>
182
+ <a name='L117'></a><a href='#L117'>117</a>
183
+ <a name='L118'></a><a href='#L118'>118</a>
184
+ <a name='L119'></a><a href='#L119'>119</a>
185
+ <a name='L120'></a><a href='#L120'>120</a>
186
+ <a name='L121'></a><a href='#L121'>121</a>
187
+ <a name='L122'></a><a href='#L122'>122</a>
188
+ <a name='L123'></a><a href='#L123'>123</a>
189
+ <a name='L124'></a><a href='#L124'>124</a>
190
+ <a name='L125'></a><a href='#L125'>125</a>
191
+ <a name='L126'></a><a href='#L126'>126</a>
192
+ <a name='L127'></a><a href='#L127'>127</a>
193
+ <a name='L128'></a><a href='#L128'>128</a>
194
+ <a name='L129'></a><a href='#L129'>129</a>
195
+ <a name='L130'></a><a href='#L130'>130</a>
196
+ <a name='L131'></a><a href='#L131'>131</a>
197
+ <a name='L132'></a><a href='#L132'>132</a>
198
+ <a name='L133'></a><a href='#L133'>133</a>
199
+ <a name='L134'></a><a href='#L134'>134</a>
200
+ <a name='L135'></a><a href='#L135'>135</a>
201
+ <a name='L136'></a><a href='#L136'>136</a>
202
+ <a name='L137'></a><a href='#L137'>137</a>
203
+ <a name='L138'></a><a href='#L138'>138</a>
204
+ <a name='L139'></a><a href='#L139'>139</a>
205
+ <a name='L140'></a><a href='#L140'>140</a>
206
+ <a name='L141'></a><a href='#L141'>141</a>
207
+ <a name='L142'></a><a href='#L142'>142</a>
208
+ <a name='L143'></a><a href='#L143'>143</a>
209
+ <a name='L144'></a><a href='#L144'>144</a>
210
+ <a name='L145'></a><a href='#L145'>145</a>
211
+ <a name='L146'></a><a href='#L146'>146</a>
212
+ <a name='L147'></a><a href='#L147'>147</a>
213
+ <a name='L148'></a><a href='#L148'>148</a>
214
+ <a name='L149'></a><a href='#L149'>149</a>
215
+ <a name='L150'></a><a href='#L150'>150</a>
216
+ <a name='L151'></a><a href='#L151'>151</a>
217
+ <a name='L152'></a><a href='#L152'>152</a>
218
+ <a name='L153'></a><a href='#L153'>153</a>
219
+ <a name='L154'></a><a href='#L154'>154</a>
220
+ <a name='L155'></a><a href='#L155'>155</a>
221
+ <a name='L156'></a><a href='#L156'>156</a>
222
+ <a name='L157'></a><a href='#L157'>157</a>
223
+ <a name='L158'></a><a href='#L158'>158</a>
224
+ <a name='L159'></a><a href='#L159'>159</a>
225
+ <a name='L160'></a><a href='#L160'>160</a>
226
+ <a name='L161'></a><a href='#L161'>161</a>
227
+ <a name='L162'></a><a href='#L162'>162</a>
228
+ <a name='L163'></a><a href='#L163'>163</a>
229
+ <a name='L164'></a><a href='#L164'>164</a>
230
+ <a name='L165'></a><a href='#L165'>165</a>
231
+ <a name='L166'></a><a href='#L166'>166</a>
232
+ <a name='L167'></a><a href='#L167'>167</a>
233
+ <a name='L168'></a><a href='#L168'>168</a>
234
+ <a name='L169'></a><a href='#L169'>169</a>
235
+ <a name='L170'></a><a href='#L170'>170</a>
236
+ <a name='L171'></a><a href='#L171'>171</a>
237
+ <a name='L172'></a><a href='#L172'>172</a>
238
+ <a name='L173'></a><a href='#L173'>173</a>
239
+ <a name='L174'></a><a href='#L174'>174</a>
240
+ <a name='L175'></a><a href='#L175'>175</a>
241
+ <a name='L176'></a><a href='#L176'>176</a>
242
+ <a name='L177'></a><a href='#L177'>177</a>
243
+ <a name='L178'></a><a href='#L178'>178</a>
244
+ <a name='L179'></a><a href='#L179'>179</a>
245
+ <a name='L180'></a><a href='#L180'>180</a>
246
+ <a name='L181'></a><a href='#L181'>181</a>
247
+ <a name='L182'></a><a href='#L182'>182</a>
248
+ <a name='L183'></a><a href='#L183'>183</a>
249
+ <a name='L184'></a><a href='#L184'>184</a>
250
+ <a name='L185'></a><a href='#L185'>185</a>
251
+ <a name='L186'></a><a href='#L186'>186</a>
252
+ <a name='L187'></a><a href='#L187'>187</a>
253
+ <a name='L188'></a><a href='#L188'>188</a>
254
+ <a name='L189'></a><a href='#L189'>189</a>
255
+ <a name='L190'></a><a href='#L190'>190</a>
256
+ <a name='L191'></a><a href='#L191'>191</a>
257
+ <a name='L192'></a><a href='#L192'>192</a>
258
+ <a name='L193'></a><a href='#L193'>193</a>
259
+ <a name='L194'></a><a href='#L194'>194</a>
260
+ <a name='L195'></a><a href='#L195'>195</a>
261
+ <a name='L196'></a><a href='#L196'>196</a>
262
+ <a name='L197'></a><a href='#L197'>197</a>
263
+ <a name='L198'></a><a href='#L198'>198</a>
264
+ <a name='L199'></a><a href='#L199'>199</a>
265
+ <a name='L200'></a><a href='#L200'>200</a>
266
+ <a name='L201'></a><a href='#L201'>201</a>
267
+ <a name='L202'></a><a href='#L202'>202</a>
268
+ <a name='L203'></a><a href='#L203'>203</a>
269
+ <a name='L204'></a><a href='#L204'>204</a>
270
+ <a name='L205'></a><a href='#L205'>205</a>
271
+ <a name='L206'></a><a href='#L206'>206</a>
272
+ <a name='L207'></a><a href='#L207'>207</a>
273
+ <a name='L208'></a><a href='#L208'>208</a>
274
+ <a name='L209'></a><a href='#L209'>209</a>
275
+ <a name='L210'></a><a href='#L210'>210</a>
276
+ <a name='L211'></a><a href='#L211'>211</a>
277
+ <a name='L212'></a><a href='#L212'>212</a>
278
+ <a name='L213'></a><a href='#L213'>213</a>
279
+ <a name='L214'></a><a href='#L214'>214</a>
280
+ <a name='L215'></a><a href='#L215'>215</a>
281
+ <a name='L216'></a><a href='#L216'>216</a>
282
+ <a name='L217'></a><a href='#L217'>217</a>
283
+ <a name='L218'></a><a href='#L218'>218</a>
284
+ <a name='L219'></a><a href='#L219'>219</a>
285
+ <a name='L220'></a><a href='#L220'>220</a>
286
+ <a name='L221'></a><a href='#L221'>221</a>
287
+ <a name='L222'></a><a href='#L222'>222</a>
288
+ <a name='L223'></a><a href='#L223'>223</a>
289
+ <a name='L224'></a><a href='#L224'>224</a>
290
+ <a name='L225'></a><a href='#L225'>225</a>
291
+ <a name='L226'></a><a href='#L226'>226</a>
292
+ <a name='L227'></a><a href='#L227'>227</a>
293
+ <a name='L228'></a><a href='#L228'>228</a>
294
+ <a name='L229'></a><a href='#L229'>229</a>
295
+ <a name='L230'></a><a href='#L230'>230</a>
296
+ <a name='L231'></a><a href='#L231'>231</a>
297
+ <a name='L232'></a><a href='#L232'>232</a>
298
+ <a name='L233'></a><a href='#L233'>233</a>
299
+ <a name='L234'></a><a href='#L234'>234</a>
300
+ <a name='L235'></a><a href='#L235'>235</a>
301
+ <a name='L236'></a><a href='#L236'>236</a>
302
+ <a name='L237'></a><a href='#L237'>237</a>
303
+ <a name='L238'></a><a href='#L238'>238</a>
304
+ <a name='L239'></a><a href='#L239'>239</a>
305
+ <a name='L240'></a><a href='#L240'>240</a>
306
+ <a name='L241'></a><a href='#L241'>241</a>
307
+ <a name='L242'></a><a href='#L242'>242</a>
308
+ <a name='L243'></a><a href='#L243'>243</a>
309
+ <a name='L244'></a><a href='#L244'>244</a>
310
+ <a name='L245'></a><a href='#L245'>245</a>
311
+ <a name='L246'></a><a href='#L246'>246</a>
312
+ <a name='L247'></a><a href='#L247'>247</a>
313
+ <a name='L248'></a><a href='#L248'>248</a>
314
+ <a name='L249'></a><a href='#L249'>249</a>
315
+ <a name='L250'></a><a href='#L250'>250</a>
316
+ <a name='L251'></a><a href='#L251'>251</a>
317
+ <a name='L252'></a><a href='#L252'>252</a>
318
+ <a name='L253'></a><a href='#L253'>253</a>
319
+ <a name='L254'></a><a href='#L254'>254</a>
320
+ <a name='L255'></a><a href='#L255'>255</a>
321
+ <a name='L256'></a><a href='#L256'>256</a>
322
+ <a name='L257'></a><a href='#L257'>257</a>
323
+ <a name='L258'></a><a href='#L258'>258</a>
324
+ <a name='L259'></a><a href='#L259'>259</a>
325
+ <a name='L260'></a><a href='#L260'>260</a>
326
+ <a name='L261'></a><a href='#L261'>261</a>
327
+ <a name='L262'></a><a href='#L262'>262</a>
328
+ <a name='L263'></a><a href='#L263'>263</a>
329
+ <a name='L264'></a><a href='#L264'>264</a>
330
+ <a name='L265'></a><a href='#L265'>265</a>
331
+ <a name='L266'></a><a href='#L266'>266</a>
332
+ <a name='L267'></a><a href='#L267'>267</a>
333
+ <a name='L268'></a><a href='#L268'>268</a>
334
+ <a name='L269'></a><a href='#L269'>269</a>
335
+ <a name='L270'></a><a href='#L270'>270</a>
336
+ <a name='L271'></a><a href='#L271'>271</a>
337
+ <a name='L272'></a><a href='#L272'>272</a>
338
+ <a name='L273'></a><a href='#L273'>273</a>
339
+ <a name='L274'></a><a href='#L274'>274</a>
340
+ <a name='L275'></a><a href='#L275'>275</a>
341
+ <a name='L276'></a><a href='#L276'>276</a>
342
+ <a name='L277'></a><a href='#L277'>277</a>
343
+ <a name='L278'></a><a href='#L278'>278</a>
344
+ <a name='L279'></a><a href='#L279'>279</a>
345
+ <a name='L280'></a><a href='#L280'>280</a>
346
+ <a name='L281'></a><a href='#L281'>281</a>
347
+ <a name='L282'></a><a href='#L282'>282</a>
348
+ <a name='L283'></a><a href='#L283'>283</a>
349
+ <a name='L284'></a><a href='#L284'>284</a>
350
+ <a name='L285'></a><a href='#L285'>285</a>
351
+ <a name='L286'></a><a href='#L286'>286</a>
352
+ <a name='L287'></a><a href='#L287'>287</a>
353
+ <a name='L288'></a><a href='#L288'>288</a>
354
+ <a name='L289'></a><a href='#L289'>289</a>
355
+ <a name='L290'></a><a href='#L290'>290</a>
356
+ <a name='L291'></a><a href='#L291'>291</a>
357
+ <a name='L292'></a><a href='#L292'>292</a>
358
+ <a name='L293'></a><a href='#L293'>293</a>
359
+ <a name='L294'></a><a href='#L294'>294</a>
360
+ <a name='L295'></a><a href='#L295'>295</a>
361
+ <a name='L296'></a><a href='#L296'>296</a>
362
+ <a name='L297'></a><a href='#L297'>297</a>
363
+ <a name='L298'></a><a href='#L298'>298</a>
364
+ <a name='L299'></a><a href='#L299'>299</a>
365
+ <a name='L300'></a><a href='#L300'>300</a>
366
+ <a name='L301'></a><a href='#L301'>301</a>
367
+ <a name='L302'></a><a href='#L302'>302</a>
368
+ <a name='L303'></a><a href='#L303'>303</a>
369
+ <a name='L304'></a><a href='#L304'>304</a>
370
+ <a name='L305'></a><a href='#L305'>305</a>
371
+ <a name='L306'></a><a href='#L306'>306</a>
372
+ <a name='L307'></a><a href='#L307'>307</a>
373
+ <a name='L308'></a><a href='#L308'>308</a>
374
+ <a name='L309'></a><a href='#L309'>309</a>
375
+ <a name='L310'></a><a href='#L310'>310</a>
376
+ <a name='L311'></a><a href='#L311'>311</a>
377
+ <a name='L312'></a><a href='#L312'>312</a>
378
+ <a name='L313'></a><a href='#L313'>313</a>
379
+ <a name='L314'></a><a href='#L314'>314</a>
380
+ <a name='L315'></a><a href='#L315'>315</a>
381
+ <a name='L316'></a><a href='#L316'>316</a>
382
+ <a name='L317'></a><a href='#L317'>317</a>
383
+ <a name='L318'></a><a href='#L318'>318</a>
384
+ <a name='L319'></a><a href='#L319'>319</a>
385
+ <a name='L320'></a><a href='#L320'>320</a>
386
+ <a name='L321'></a><a href='#L321'>321</a>
387
+ <a name='L322'></a><a href='#L322'>322</a>
388
+ <a name='L323'></a><a href='#L323'>323</a>
389
+ <a name='L324'></a><a href='#L324'>324</a>
390
+ <a name='L325'></a><a href='#L325'>325</a>
391
+ <a name='L326'></a><a href='#L326'>326</a>
392
+ <a name='L327'></a><a href='#L327'>327</a>
393
+ <a name='L328'></a><a href='#L328'>328</a>
394
+ <a name='L329'></a><a href='#L329'>329</a>
395
+ <a name='L330'></a><a href='#L330'>330</a>
396
+ <a name='L331'></a><a href='#L331'>331</a>
397
+ <a name='L332'></a><a href='#L332'>332</a>
398
+ <a name='L333'></a><a href='#L333'>333</a>
399
+ <a name='L334'></a><a href='#L334'>334</a>
400
+ <a name='L335'></a><a href='#L335'>335</a>
401
+ <a name='L336'></a><a href='#L336'>336</a>
402
+ <a name='L337'></a><a href='#L337'>337</a>
403
+ <a name='L338'></a><a href='#L338'>338</a>
404
+ <a name='L339'></a><a href='#L339'>339</a>
405
+ <a name='L340'></a><a href='#L340'>340</a>
406
+ <a name='L341'></a><a href='#L341'>341</a>
407
+ <a name='L342'></a><a href='#L342'>342</a>
408
+ <a name='L343'></a><a href='#L343'>343</a>
409
+ <a name='L344'></a><a href='#L344'>344</a>
410
+ <a name='L345'></a><a href='#L345'>345</a>
411
+ <a name='L346'></a><a href='#L346'>346</a>
412
+ <a name='L347'></a><a href='#L347'>347</a>
413
+ <a name='L348'></a><a href='#L348'>348</a>
414
+ <a name='L349'></a><a href='#L349'>349</a>
415
+ <a name='L350'></a><a href='#L350'>350</a>
416
+ <a name='L351'></a><a href='#L351'>351</a>
417
+ <a name='L352'></a><a href='#L352'>352</a>
418
+ <a name='L353'></a><a href='#L353'>353</a>
419
+ <a name='L354'></a><a href='#L354'>354</a>
420
+ <a name='L355'></a><a href='#L355'>355</a>
421
+ <a name='L356'></a><a href='#L356'>356</a>
422
+ <a name='L357'></a><a href='#L357'>357</a>
423
+ <a name='L358'></a><a href='#L358'>358</a>
424
+ <a name='L359'></a><a href='#L359'>359</a>
425
+ <a name='L360'></a><a href='#L360'>360</a>
426
+ <a name='L361'></a><a href='#L361'>361</a>
427
+ <a name='L362'></a><a href='#L362'>362</a>
428
+ <a name='L363'></a><a href='#L363'>363</a>
429
+ <a name='L364'></a><a href='#L364'>364</a>
430
+ <a name='L365'></a><a href='#L365'>365</a>
431
+ <a name='L366'></a><a href='#L366'>366</a>
432
+ <a name='L367'></a><a href='#L367'>367</a>
433
+ <a name='L368'></a><a href='#L368'>368</a>
434
+ <a name='L369'></a><a href='#L369'>369</a>
435
+ <a name='L370'></a><a href='#L370'>370</a>
436
+ <a name='L371'></a><a href='#L371'>371</a>
437
+ <a name='L372'></a><a href='#L372'>372</a>
438
+ <a name='L373'></a><a href='#L373'>373</a>
439
+ <a name='L374'></a><a href='#L374'>374</a>
440
+ <a name='L375'></a><a href='#L375'>375</a>
441
+ <a name='L376'></a><a href='#L376'>376</a>
442
+ <a name='L377'></a><a href='#L377'>377</a>
443
+ <a name='L378'></a><a href='#L378'>378</a>
444
+ <a name='L379'></a><a href='#L379'>379</a>
445
+ <a name='L380'></a><a href='#L380'>380</a>
446
+ <a name='L381'></a><a href='#L381'>381</a>
447
+ <a name='L382'></a><a href='#L382'>382</a>
448
+ <a name='L383'></a><a href='#L383'>383</a>
449
+ <a name='L384'></a><a href='#L384'>384</a>
450
+ <a name='L385'></a><a href='#L385'>385</a>
451
+ <a name='L386'></a><a href='#L386'>386</a>
452
+ <a name='L387'></a><a href='#L387'>387</a>
453
+ <a name='L388'></a><a href='#L388'>388</a>
454
+ <a name='L389'></a><a href='#L389'>389</a>
455
+ <a name='L390'></a><a href='#L390'>390</a>
456
+ <a name='L391'></a><a href='#L391'>391</a>
457
+ <a name='L392'></a><a href='#L392'>392</a>
458
+ <a name='L393'></a><a href='#L393'>393</a>
459
+ <a name='L394'></a><a href='#L394'>394</a>
460
+ <a name='L395'></a><a href='#L395'>395</a>
461
+ <a name='L396'></a><a href='#L396'>396</a>
462
+ <a name='L397'></a><a href='#L397'>397</a>
463
+ <a name='L398'></a><a href='#L398'>398</a>
464
+ <a name='L399'></a><a href='#L399'>399</a>
465
+ <a name='L400'></a><a href='#L400'>400</a>
466
+ <a name='L401'></a><a href='#L401'>401</a>
467
+ <a name='L402'></a><a href='#L402'>402</a>
468
+ <a name='L403'></a><a href='#L403'>403</a>
469
+ <a name='L404'></a><a href='#L404'>404</a>
470
+ <a name='L405'></a><a href='#L405'>405</a>
471
+ <a name='L406'></a><a href='#L406'>406</a>
472
+ <a name='L407'></a><a href='#L407'>407</a>
473
+ <a name='L408'></a><a href='#L408'>408</a>
474
+ <a name='L409'></a><a href='#L409'>409</a>
475
+ <a name='L410'></a><a href='#L410'>410</a>
476
+ <a name='L411'></a><a href='#L411'>411</a>
477
+ <a name='L412'></a><a href='#L412'>412</a>
478
+ <a name='L413'></a><a href='#L413'>413</a>
479
+ <a name='L414'></a><a href='#L414'>414</a>
480
+ <a name='L415'></a><a href='#L415'>415</a>
481
+ <a name='L416'></a><a href='#L416'>416</a>
482
+ <a name='L417'></a><a href='#L417'>417</a></td><td class="line-coverage quiet"><span class="cline-any cline-yes">1x</span>
483
+ <span class="cline-any cline-neutral">&nbsp;</span>
484
+ <span class="cline-any cline-neutral">&nbsp;</span>
485
+ <span class="cline-any cline-neutral">&nbsp;</span>
486
+ <span class="cline-any cline-neutral">&nbsp;</span>
487
+ <span class="cline-any cline-neutral">&nbsp;</span>
488
+ <span class="cline-any cline-neutral">&nbsp;</span>
489
+ <span class="cline-any cline-neutral">&nbsp;</span>
490
+ <span class="cline-any cline-neutral">&nbsp;</span>
491
+ <span class="cline-any cline-neutral">&nbsp;</span>
492
+ <span class="cline-any cline-neutral">&nbsp;</span>
493
+ <span class="cline-any cline-neutral">&nbsp;</span>
494
+ <span class="cline-any cline-neutral">&nbsp;</span>
495
+ <span class="cline-any cline-neutral">&nbsp;</span>
496
+ <span class="cline-any cline-neutral">&nbsp;</span>
497
+ <span class="cline-any cline-neutral">&nbsp;</span>
498
+ <span class="cline-any cline-neutral">&nbsp;</span>
499
+ <span class="cline-any cline-neutral">&nbsp;</span>
500
+ <span class="cline-any cline-neutral">&nbsp;</span>
501
+ <span class="cline-any cline-neutral">&nbsp;</span>
502
+ <span class="cline-any cline-neutral">&nbsp;</span>
503
+ <span class="cline-any cline-neutral">&nbsp;</span>
504
+ <span class="cline-any cline-neutral">&nbsp;</span>
505
+ <span class="cline-any cline-neutral">&nbsp;</span>
506
+ <span class="cline-any cline-neutral">&nbsp;</span>
507
+ <span class="cline-any cline-neutral">&nbsp;</span>
508
+ <span class="cline-any cline-neutral">&nbsp;</span>
509
+ <span class="cline-any cline-neutral">&nbsp;</span>
510
+ <span class="cline-any cline-neutral">&nbsp;</span>
511
+ <span class="cline-any cline-neutral">&nbsp;</span>
512
+ <span class="cline-any cline-neutral">&nbsp;</span>
513
+ <span class="cline-any cline-neutral">&nbsp;</span>
514
+ <span class="cline-any cline-neutral">&nbsp;</span>
515
+ <span class="cline-any cline-neutral">&nbsp;</span>
516
+ <span class="cline-any cline-neutral">&nbsp;</span>
517
+ <span class="cline-any cline-neutral">&nbsp;</span>
518
+ <span class="cline-any cline-neutral">&nbsp;</span>
519
+ <span class="cline-any cline-neutral">&nbsp;</span>
520
+ <span class="cline-any cline-neutral">&nbsp;</span>
521
+ <span class="cline-any cline-neutral">&nbsp;</span>
522
+ <span class="cline-any cline-neutral">&nbsp;</span>
523
+ <span class="cline-any cline-neutral">&nbsp;</span>
524
+ <span class="cline-any cline-neutral">&nbsp;</span>
525
+ <span class="cline-any cline-neutral">&nbsp;</span>
526
+ <span class="cline-any cline-neutral">&nbsp;</span>
527
+ <span class="cline-any cline-neutral">&nbsp;</span>
528
+ <span class="cline-any cline-neutral">&nbsp;</span>
529
+ <span class="cline-any cline-neutral">&nbsp;</span>
530
+ <span class="cline-any cline-neutral">&nbsp;</span>
531
+ <span class="cline-any cline-neutral">&nbsp;</span>
532
+ <span class="cline-any cline-neutral">&nbsp;</span>
533
+ <span class="cline-any cline-neutral">&nbsp;</span>
534
+ <span class="cline-any cline-neutral">&nbsp;</span>
535
+ <span class="cline-any cline-neutral">&nbsp;</span>
536
+ <span class="cline-any cline-neutral">&nbsp;</span>
537
+ <span class="cline-any cline-neutral">&nbsp;</span>
538
+ <span class="cline-any cline-neutral">&nbsp;</span>
539
+ <span class="cline-any cline-neutral">&nbsp;</span>
540
+ <span class="cline-any cline-neutral">&nbsp;</span>
541
+ <span class="cline-any cline-neutral">&nbsp;</span>
542
+ <span class="cline-any cline-neutral">&nbsp;</span>
543
+ <span class="cline-any cline-neutral">&nbsp;</span>
544
+ <span class="cline-any cline-neutral">&nbsp;</span>
545
+ <span class="cline-any cline-neutral">&nbsp;</span>
546
+ <span class="cline-any cline-yes">1x</span>
547
+ <span class="cline-any cline-neutral">&nbsp;</span>
548
+ <span class="cline-any cline-neutral">&nbsp;</span>
549
+ <span class="cline-any cline-yes">1x</span>
550
+ <span class="cline-any cline-yes">3x</span>
551
+ <span class="cline-any cline-yes">3x</span>
552
+ <span class="cline-any cline-neutral">&nbsp;</span>
553
+ <span class="cline-any cline-yes">1x</span>
554
+ <span class="cline-any cline-yes">26x</span>
555
+ <span class="cline-any cline-neutral">&nbsp;</span>
556
+ <span class="cline-any cline-yes">26x</span>
557
+ <span class="cline-any cline-yes">2x</span>
558
+ <span class="cline-any cline-yes">2x</span>
559
+ <span class="cline-any cline-yes">2x</span>
560
+ <span class="cline-any cline-yes">2x</span>
561
+ <span class="cline-any cline-yes">2x</span>
562
+ <span class="cline-any cline-yes">2x</span>
563
+ <span class="cline-any cline-neutral">&nbsp;</span>
564
+ <span class="cline-any cline-neutral">&nbsp;</span>
565
+ <span class="cline-any cline-neutral">&nbsp;</span>
566
+ <span class="cline-any cline-yes">24x</span>
567
+ <span class="cline-any cline-yes">24x</span>
568
+ <span class="cline-any cline-yes">24x</span>
569
+ <span class="cline-any cline-neutral">&nbsp;</span>
570
+ <span class="cline-any cline-yes">26x</span>
571
+ <span class="cline-any cline-neutral">&nbsp;</span>
572
+ <span class="cline-any cline-neutral">&nbsp;</span>
573
+ <span class="cline-any cline-yes">26x</span>
574
+ <span class="cline-any cline-yes">26x</span>
575
+ <span class="cline-any cline-yes">26x</span>
576
+ <span class="cline-any cline-yes">26x</span>
577
+ <span class="cline-any cline-yes">26x</span>
578
+ <span class="cline-any cline-neutral">&nbsp;</span>
579
+ <span class="cline-any cline-yes">28x</span>
580
+ <span class="cline-any cline-yes">28x</span>
581
+ <span class="cline-any cline-neutral">&nbsp;</span>
582
+ <span class="cline-any cline-neutral">&nbsp;</span>
583
+ <span class="cline-any cline-yes">28x</span>
584
+ <span class="cline-any cline-yes">28x</span>
585
+ <span class="cline-any cline-no">&nbsp;</span>
586
+ <span class="cline-any cline-no">&nbsp;</span>
587
+ <span class="cline-any cline-neutral">&nbsp;</span>
588
+ <span class="cline-any cline-neutral">&nbsp;</span>
589
+ <span class="cline-any cline-yes">28x</span>
590
+ <span class="cline-any cline-yes">28x</span>
591
+ <span class="cline-any cline-no">&nbsp;</span>
592
+ <span class="cline-any cline-no">&nbsp;</span>
593
+ <span class="cline-any cline-no">&nbsp;</span>
594
+ <span class="cline-any cline-no">&nbsp;</span>
595
+ <span class="cline-any cline-no">&nbsp;</span>
596
+ <span class="cline-any cline-no">&nbsp;</span>
597
+ <span class="cline-any cline-no">&nbsp;</span>
598
+ <span class="cline-any cline-no">&nbsp;</span>
599
+ <span class="cline-any cline-neutral">&nbsp;</span>
600
+ <span class="cline-any cline-neutral">&nbsp;</span>
601
+ <span class="cline-any cline-neutral">&nbsp;</span>
602
+ <span class="cline-any cline-neutral">&nbsp;</span>
603
+ <span class="cline-any cline-neutral">&nbsp;</span>
604
+ <span class="cline-any cline-yes">28x</span>
605
+ <span class="cline-any cline-neutral">&nbsp;</span>
606
+ <span class="cline-any cline-neutral">&nbsp;</span>
607
+ <span class="cline-any cline-neutral">&nbsp;</span>
608
+ <span class="cline-any cline-neutral">&nbsp;</span>
609
+ <span class="cline-any cline-yes">28x</span>
610
+ <span class="cline-any cline-no">&nbsp;</span>
611
+ <span class="cline-any cline-no">&nbsp;</span>
612
+ <span class="cline-any cline-neutral">&nbsp;</span>
613
+ <span class="cline-any cline-neutral">&nbsp;</span>
614
+ <span class="cline-any cline-yes">26x</span>
615
+ <span class="cline-any cline-yes">26x</span>
616
+ <span class="cline-any cline-yes">26x</span>
617
+ <span class="cline-any cline-yes">28x</span>
618
+ <span class="cline-any cline-no">&nbsp;</span>
619
+ <span class="cline-any cline-no">&nbsp;</span>
620
+ <span class="cline-any cline-neutral">&nbsp;</span>
621
+ <span class="cline-any cline-neutral">&nbsp;</span>
622
+ <span class="cline-any cline-neutral">&nbsp;</span>
623
+ <span class="cline-any cline-yes">26x</span>
624
+ <span class="cline-any cline-yes">26x</span>
625
+ <span class="cline-any cline-yes">26x</span>
626
+ <span class="cline-any cline-yes">28x</span>
627
+ <span class="cline-any cline-yes">2x</span>
628
+ <span class="cline-any cline-yes">2x</span>
629
+ <span class="cline-any cline-neutral">&nbsp;</span>
630
+ <span class="cline-any cline-neutral">&nbsp;</span>
631
+ <span class="cline-any cline-yes">24x</span>
632
+ <span class="cline-any cline-yes">28x</span>
633
+ <span class="cline-any cline-yes">4x</span>
634
+ <span class="cline-any cline-yes">4x</span>
635
+ <span class="cline-any cline-yes">4x</span>
636
+ <span class="cline-any cline-yes">4x</span>
637
+ <span class="cline-any cline-neutral">&nbsp;</span>
638
+ <span class="cline-any cline-neutral">&nbsp;</span>
639
+ <span class="cline-any cline-yes">20x</span>
640
+ <span class="cline-any cline-yes">24x</span>
641
+ <span class="cline-any cline-no">&nbsp;</span>
642
+ <span class="cline-any cline-no">&nbsp;</span>
643
+ <span class="cline-any cline-no">&nbsp;</span>
644
+ <span class="cline-any cline-no">&nbsp;</span>
645
+ <span class="cline-any cline-no">&nbsp;</span>
646
+ <span class="cline-any cline-no">&nbsp;</span>
647
+ <span class="cline-any cline-no">&nbsp;</span>
648
+ <span class="cline-any cline-neutral">&nbsp;</span>
649
+ <span class="cline-any cline-yes">20x</span>
650
+ <span class="cline-any cline-yes">24x</span>
651
+ <span class="cline-any cline-neutral">&nbsp;</span>
652
+ <span class="cline-any cline-neutral">&nbsp;</span>
653
+ <span class="cline-any cline-yes">19x</span>
654
+ <span class="cline-any cline-yes">24x</span>
655
+ <span class="cline-any cline-neutral">&nbsp;</span>
656
+ <span class="cline-any cline-neutral">&nbsp;</span>
657
+ <span class="cline-any cline-neutral">&nbsp;</span>
658
+ <span class="cline-any cline-neutral">&nbsp;</span>
659
+ <span class="cline-any cline-neutral">&nbsp;</span>
660
+ <span class="cline-any cline-yes">17x</span>
661
+ <span class="cline-any cline-neutral">&nbsp;</span>
662
+ <span class="cline-any cline-neutral">&nbsp;</span>
663
+ <span class="cline-any cline-neutral">&nbsp;</span>
664
+ <span class="cline-any cline-neutral">&nbsp;</span>
665
+ <span class="cline-any cline-yes">17x</span>
666
+ <span class="cline-any cline-yes">24x</span>
667
+ <span class="cline-any cline-yes">5x</span>
668
+ <span class="cline-any cline-yes">5x</span>
669
+ <span class="cline-any cline-neutral">&nbsp;</span>
670
+ <span class="cline-any cline-neutral">&nbsp;</span>
671
+ <span class="cline-any cline-yes">12x</span>
672
+ <span class="cline-any cline-yes">24x</span>
673
+ <span class="cline-any cline-no">&nbsp;</span>
674
+ <span class="cline-any cline-no">&nbsp;</span>
675
+ <span class="cline-any cline-no">&nbsp;</span>
676
+ <span class="cline-any cline-neutral">&nbsp;</span>
677
+ <span class="cline-any cline-neutral">&nbsp;</span>
678
+ <span class="cline-any cline-yes">12x</span>
679
+ <span class="cline-any cline-yes">24x</span>
680
+ <span class="cline-any cline-no">&nbsp;</span>
681
+ <span class="cline-any cline-no">&nbsp;</span>
682
+ <span class="cline-any cline-no">&nbsp;</span>
683
+ <span class="cline-any cline-no">&nbsp;</span>
684
+ <span class="cline-any cline-no">&nbsp;</span>
685
+ <span class="cline-any cline-no">&nbsp;</span>
686
+ <span class="cline-any cline-no">&nbsp;</span>
687
+ <span class="cline-any cline-no">&nbsp;</span>
688
+ <span class="cline-any cline-no">&nbsp;</span>
689
+ <span class="cline-any cline-no">&nbsp;</span>
690
+ <span class="cline-any cline-neutral">&nbsp;</span>
691
+ <span class="cline-any cline-neutral">&nbsp;</span>
692
+ <span class="cline-any cline-yes">12x</span>
693
+ <span class="cline-any cline-yes">12x</span>
694
+ <span class="cline-any cline-yes">12x</span>
695
+ <span class="cline-any cline-yes">12x</span>
696
+ <span class="cline-any cline-yes">18x</span>
697
+ <span class="cline-any cline-yes">11x</span>
698
+ <span class="cline-any cline-yes">11x</span>
699
+ <span class="cline-any cline-yes">11x</span>
700
+ <span class="cline-any cline-yes">11x</span>
701
+ <span class="cline-any cline-yes">11x</span>
702
+ <span class="cline-any cline-yes">11x</span>
703
+ <span class="cline-any cline-yes">11x</span>
704
+ <span class="cline-any cline-yes">11x</span>
705
+ <span class="cline-any cline-yes">11x</span>
706
+ <span class="cline-any cline-yes">11x</span>
707
+ <span class="cline-any cline-yes">11x</span>
708
+ <span class="cline-any cline-neutral">&nbsp;</span>
709
+ <span class="cline-any cline-yes">1x</span>
710
+ <span class="cline-any cline-yes">1x</span>
711
+ <span class="cline-any cline-neutral">&nbsp;</span>
712
+ <span class="cline-any cline-neutral">&nbsp;</span>
713
+ <span class="cline-any cline-neutral">&nbsp;</span>
714
+ <span class="cline-any cline-neutral">&nbsp;</span>
715
+ <span class="cline-any cline-neutral">&nbsp;</span>
716
+ <span class="cline-any cline-neutral">&nbsp;</span>
717
+ <span class="cline-any cline-neutral">&nbsp;</span>
718
+ <span class="cline-any cline-neutral">&nbsp;</span>
719
+ <span class="cline-any cline-neutral">&nbsp;</span>
720
+ <span class="cline-any cline-neutral">&nbsp;</span>
721
+ <span class="cline-any cline-neutral">&nbsp;</span>
722
+ <span class="cline-any cline-neutral">&nbsp;</span>
723
+ <span class="cline-any cline-neutral">&nbsp;</span>
724
+ <span class="cline-any cline-neutral">&nbsp;</span>
725
+ <span class="cline-any cline-yes">17x</span>
726
+ <span class="cline-any cline-yes">17x</span>
727
+ <span class="cline-any cline-yes">17x</span>
728
+ <span class="cline-any cline-yes">17x</span>
729
+ <span class="cline-any cline-yes">17x</span>
730
+ <span class="cline-any cline-yes">17x</span>
731
+ <span class="cline-any cline-yes">17x</span>
732
+ <span class="cline-any cline-neutral">&nbsp;</span>
733
+ <span class="cline-any cline-yes">17x</span>
734
+ <span class="cline-any cline-yes">34x</span>
735
+ <span class="cline-any cline-yes">34x</span>
736
+ <span class="cline-any cline-yes">15x</span>
737
+ <span class="cline-any cline-yes">30x</span>
738
+ <span class="cline-any cline-yes">15x</span>
739
+ <span class="cline-any cline-yes">15x</span>
740
+ <span class="cline-any cline-yes">34x</span>
741
+ <span class="cline-any cline-neutral">&nbsp;</span>
742
+ <span class="cline-any cline-neutral">&nbsp;</span>
743
+ <span class="cline-any cline-yes">17x</span>
744
+ <span class="cline-any cline-yes">17x</span>
745
+ <span class="cline-any cline-yes">17x</span>
746
+ <span class="cline-any cline-yes">17x</span>
747
+ <span class="cline-any cline-yes">17x</span>
748
+ <span class="cline-any cline-yes">17x</span>
749
+ <span class="cline-any cline-neutral">&nbsp;</span>
750
+ <span class="cline-any cline-yes">15x</span>
751
+ <span class="cline-any cline-yes">15x</span>
752
+ <span class="cline-any cline-yes">15x</span>
753
+ <span class="cline-any cline-yes">501x</span>
754
+ <span class="cline-any cline-yes">501x</span>
755
+ <span class="cline-any cline-yes">15x</span>
756
+ <span class="cline-any cline-yes">15x</span>
757
+ <span class="cline-any cline-neutral">&nbsp;</span>
758
+ <span class="cline-any cline-neutral">&nbsp;</span>
759
+ <span class="cline-any cline-yes">15x</span>
760
+ <span class="cline-any cline-yes">15x</span>
761
+ <span class="cline-any cline-yes">15x</span>
762
+ <span class="cline-any cline-yes">15x</span>
763
+ <span class="cline-any cline-yes">15x</span>
764
+ <span class="cline-any cline-neutral">&nbsp;</span>
765
+ <span class="cline-any cline-neutral">&nbsp;</span>
766
+ <span class="cline-any cline-neutral">&nbsp;</span>
767
+ <span class="cline-any cline-neutral">&nbsp;</span>
768
+ <span class="cline-any cline-neutral">&nbsp;</span>
769
+ <span class="cline-any cline-neutral">&nbsp;</span>
770
+ <span class="cline-any cline-neutral">&nbsp;</span>
771
+ <span class="cline-any cline-neutral">&nbsp;</span>
772
+ <span class="cline-any cline-neutral">&nbsp;</span>
773
+ <span class="cline-any cline-neutral">&nbsp;</span>
774
+ <span class="cline-any cline-yes">1x</span>
775
+ <span class="cline-any cline-neutral">&nbsp;</span>
776
+ <span class="cline-any cline-neutral">&nbsp;</span>
777
+ <span class="cline-any cline-yes">103x</span>
778
+ <span class="cline-any cline-yes">103x</span>
779
+ <span class="cline-any cline-yes">103x</span>
780
+ <span class="cline-any cline-neutral">&nbsp;</span>
781
+ <span class="cline-any cline-neutral">&nbsp;</span>
782
+ <span class="cline-any cline-neutral">&nbsp;</span>
783
+ <span class="cline-any cline-neutral">&nbsp;</span>
784
+ <span class="cline-any cline-neutral">&nbsp;</span>
785
+ <span class="cline-any cline-neutral">&nbsp;</span>
786
+ <span class="cline-any cline-yes">4x</span>
787
+ <span class="cline-any cline-yes">4x</span>
788
+ <span class="cline-any cline-yes">4x</span>
789
+ <span class="cline-any cline-yes">4x</span>
790
+ <span class="cline-any cline-neutral">&nbsp;</span>
791
+ <span class="cline-any cline-yes">11x</span>
792
+ <span class="cline-any cline-yes">11x</span>
793
+ <span class="cline-any cline-yes">11x</span>
794
+ <span class="cline-any cline-yes">11x</span>
795
+ <span class="cline-any cline-no">&nbsp;</span>
796
+ <span class="cline-any cline-no">&nbsp;</span>
797
+ <span class="cline-any cline-neutral">&nbsp;</span>
798
+ <span class="cline-any cline-yes">2x</span>
799
+ <span class="cline-any cline-yes">2x</span>
800
+ <span class="cline-any cline-yes">2x</span>
801
+ <span class="cline-any cline-neutral">&nbsp;</span>
802
+ <span class="cline-any cline-neutral">&nbsp;</span>
803
+ <span class="cline-any cline-yes">4x</span>
804
+ <span class="cline-any cline-yes">4x</span>
805
+ <span class="cline-any cline-yes">10x</span>
806
+ <span class="cline-any cline-yes">10x</span>
807
+ <span class="cline-any cline-yes">10x</span>
808
+ <span class="cline-any cline-yes">4x</span>
809
+ <span class="cline-any cline-yes">4x</span>
810
+ <span class="cline-any cline-neutral">&nbsp;</span>
811
+ <span class="cline-any cline-yes">13x</span>
812
+ <span class="cline-any cline-yes">13x</span>
813
+ <span class="cline-any cline-yes">13x</span>
814
+ <span class="cline-any cline-yes">13x</span>
815
+ <span class="cline-any cline-yes">13x</span>
816
+ <span class="cline-any cline-yes">1x</span>
817
+ <span class="cline-any cline-no">&nbsp;</span>
818
+ <span class="cline-any cline-yes">13x</span>
819
+ <span class="cline-any cline-no">&nbsp;</span>
820
+ <span class="cline-any cline-no">&nbsp;</span>
821
+ <span class="cline-any cline-neutral">&nbsp;</span>
822
+ <span class="cline-any cline-yes">3x</span>
823
+ <span class="cline-any cline-neutral">&nbsp;</span>
824
+ <span class="cline-any cline-neutral">&nbsp;</span>
825
+ <span class="cline-any cline-yes">3x</span>
826
+ <span class="cline-any cline-yes">3x</span>
827
+ <span class="cline-any cline-yes">3x</span>
828
+ <span class="cline-any cline-yes">3x</span>
829
+ <span class="cline-any cline-yes">3x</span>
830
+ <span class="cline-any cline-yes">3x</span>
831
+ <span class="cline-any cline-neutral">&nbsp;</span>
832
+ <span class="cline-any cline-neutral">&nbsp;</span>
833
+ <span class="cline-any cline-neutral">&nbsp;</span>
834
+ <span class="cline-any cline-yes">1x</span>
835
+ <span class="cline-any cline-yes">1x</span>
836
+ <span class="cline-any cline-yes">1x</span>
837
+ <span class="cline-any cline-yes">1x</span>
838
+ <span class="cline-any cline-yes">1x</span>
839
+ <span class="cline-any cline-yes">1x</span>
840
+ <span class="cline-any cline-neutral">&nbsp;</span>
841
+ <span class="cline-any cline-neutral">&nbsp;</span>
842
+ <span class="cline-any cline-yes">7x</span>
843
+ <span class="cline-any cline-yes">7x</span>
844
+ <span class="cline-any cline-yes">7x</span>
845
+ <span class="cline-any cline-yes">7x</span>
846
+ <span class="cline-any cline-yes">7x</span>
847
+ <span class="cline-any cline-yes">7x</span>
848
+ <span class="cline-any cline-yes">7x</span>
849
+ <span class="cline-any cline-yes">248x</span>
850
+ <span class="cline-any cline-yes">248x</span>
851
+ <span class="cline-any cline-yes">26x</span>
852
+ <span class="cline-any cline-yes">26x</span>
853
+ <span class="cline-any cline-yes">26x</span>
854
+ <span class="cline-any cline-yes">26x</span>
855
+ <span class="cline-any cline-yes">248x</span>
856
+ <span class="cline-any cline-yes">4x</span>
857
+ <span class="cline-any cline-yes">4x</span>
858
+ <span class="cline-any cline-yes">4x</span>
859
+ <span class="cline-any cline-yes">4x</span>
860
+ <span class="cline-any cline-yes">218x</span>
861
+ <span class="cline-any cline-yes">218x</span>
862
+ <span class="cline-any cline-yes">218x</span>
863
+ <span class="cline-any cline-yes">24x</span>
864
+ <span class="cline-any cline-yes">194x</span>
865
+ <span class="cline-any cline-yes">248x</span>
866
+ <span class="cline-any cline-yes">6x</span>
867
+ <span class="cline-any cline-yes">6x</span>
868
+ <span class="cline-any cline-yes">6x</span>
869
+ <span class="cline-any cline-yes">6x</span>
870
+ <span class="cline-any cline-yes">6x</span>
871
+ <span class="cline-any cline-yes">212x</span>
872
+ <span class="cline-any cline-yes">212x</span>
873
+ <span class="cline-any cline-yes">7x</span>
874
+ <span class="cline-any cline-yes">7x</span>
875
+ <span class="cline-any cline-yes">7x</span>
876
+ <span class="cline-any cline-neutral">&nbsp;</span>
877
+ <span class="cline-any cline-neutral">&nbsp;</span>
878
+ <span class="cline-any cline-yes">1x</span>
879
+ <span class="cline-any cline-no">&nbsp;</span>
880
+ <span class="cline-any cline-no">&nbsp;</span>
881
+ <span class="cline-any cline-no">&nbsp;</span>
882
+ <span class="cline-any cline-no">&nbsp;</span>
883
+ <span class="cline-any cline-no">&nbsp;</span>
884
+ <span class="cline-any cline-no">&nbsp;</span>
885
+ <span class="cline-any cline-no">&nbsp;</span>
886
+ <span class="cline-any cline-neutral">&nbsp;</span>
887
+ <span class="cline-any cline-neutral">&nbsp;</span>
888
+ <span class="cline-any cline-yes">1x</span>
889
+ <span class="cline-any cline-yes">10x</span>
890
+ <span class="cline-any cline-yes">10x</span>
891
+ <span class="cline-any cline-yes">10x</span>
892
+ <span class="cline-any cline-no">&nbsp;</span>
893
+ <span class="cline-any cline-no">&nbsp;</span>
894
+ <span class="cline-any cline-no">&nbsp;</span>
895
+ <span class="cline-any cline-no">&nbsp;</span>
896
+ <span class="cline-any cline-yes">10x</span>
897
+ <span class="cline-any cline-yes">10x</span>
898
+ <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import type { WhereNode } from '@spooky-sync/query-builder';
899
+ import type { OrderBy, Row } from './cache-engine';
900
+ import { stableKey } from './relation-resolver';
901
+ &nbsp;
902
+ /**
903
+ * Translate the BOUNDED set of SurrealQL statements the client actually emits
904
+ * into engine-neutral operations the SQLite backend executes. This is NOT a
905
+ * general SurrealQL parser — it recognizes exactly the shapes produced by the
906
+ * `surql` helper and the handful of literal queries in the codebase. Anything
907
+ * unrecognized throws (with the offending SQL) so gaps surface loudly during a
908
+ * trial rather than silently returning wrong data.
909
+ *
910
+ * The arbitrary user SELECT (`config.surql`, with nested `.related()`
911
+ * subqueries) is intentionally NOT handled here — it flows through
912
+ * `engine.select(plan)` instead, so the translator never faces an unbounded
913
+ * query shape.
914
+ */
915
+ &nbsp;
916
+ export type SqlOp =
917
+ | { kind: 'getById'; id: unknown; select?: string[]; value?: string }
918
+ | {
919
+ kind: 'selectByIds';
920
+ ids: unknown[];
921
+ select?: string[];
922
+ orderBy?: OrderBy;
923
+ value?: string;
924
+ limit?: number;
925
+ start?: number;
926
+ }
927
+ | {
928
+ kind: 'selectTable';
929
+ table: string;
930
+ where?: WhereNode[];
931
+ orderBy?: OrderBy;
932
+ select?: string[];
933
+ value?: string;
934
+ limit?: number;
935
+ start?: number;
936
+ }
937
+ /** `SELECT count() FROM t [WHERE …] GROUP ALL` — one `{ count }` row. */
938
+ | { kind: 'count'; table: string; where?: WhereNode[] }
939
+ /** `INFO FOR DB` — the table list, in SurrealDB's `{ tables: {…} }` shape. */
940
+ | { kind: 'infoForDb' }
941
+ | { kind: 'upsert'; id: unknown; data: Row; mode: 'replace' | 'merge' }
942
+ | { kind: 'updateSet'; id: unknown; sets: SetClause[]; returnNone: boolean }
943
+ | { kind: 'delete'; id: unknown }
944
+ | { kind: 'deleteAll'; table: string }
945
+ | { kind: 'let'; var: string; inner: SqlOp }
946
+ | { kind: 'return'; entries: { key: string; var: string }[] }
947
+ | { kind: 'noop' };
948
+ &nbsp;
949
+ export interface SetClause {
950
+ path: string;
951
+ op: '=' | '+=' | '-=';
952
+ value: unknown;
953
+ }
954
+ &nbsp;
955
+ export interface TranslatedQuery {
956
+ /** True for a `BEGIN TRANSACTION … COMMIT` block — the engine prepends a
957
+ * `null` begin-result so `surql.seal`'s `idx+1` extraction still lines up. */
958
+ transaction: boolean;
959
+ ops: SqlOp[];
960
+ }
961
+ &nbsp;
962
+ const rid = (v: unknown): unknown =&gt; v;
963
+ &nbsp;
964
+ /** Table name from a record id value (`table:id` string or RecordId). */
965
+ export function tableOf(id: unknown): string {
966
+ return stableKey(id).split(':')[0];
967
+ }
968
+ &nbsp;
969
+ export function translateSurql(sql: string, vars: Record&lt;string, unknown&gt;): TranslatedQuery {
970
+ const trimmed = sql.trim().replace(/;\s*$/, '');
971
+ &nbsp;
972
+ if (/^BEGIN\s+TRANSACTION/i.test(trimmed)) {
973
+ const inner = trimmed
974
+ .replace(/^BEGIN\s+TRANSACTION\s*;?/i, '')
975
+ .replace(/;?\s*COMMIT\s+TRANSACTION\s*$/i, '');
976
+ const ops = splitStatements(inner).map((s) =&gt; translateStatement(s, vars));
977
+ return { transaction: true, ops };
978
+ }
979
+ &nbsp;
980
+ // A plain multi-statement string (e.g. `DEFINE DATABASE x; USE DB x`) — split
981
+ // and translate each. Single statement is just the one-element case.
982
+ const parts = splitStatements(trimmed);
983
+ return { transaction: false, ops: parts.map((s) =&gt; translateStatement(s, vars)) };
984
+ }
985
+ &nbsp;
986
+ function splitStatements(block: string): string[] {
987
+ // Statements in the client's tx blocks never contain a bare `;` inside a
988
+ // string/paren, so a simple split is sufficient for this bounded vocabulary.
989
+ return block
990
+ .split(';')
991
+ .map((s) =&gt; s.trim())
992
+ .filter(Boolean);
993
+ }
994
+ &nbsp;
995
+ function translateStatement(stmt: string, vars: Record&lt;string, unknown&gt;): SqlOp {
996
+ const s = stmt.trim();
997
+ &nbsp;
998
+ // LET $var = ( &lt;inner statement&gt; ) — bind the inner result into query scope.
999
+ let mLet = /^LET\s+\$(\w+)\s*=\s*\(([\s\S]+)\)$/i.exec(s);
1000
+ if (mLet) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
1001
+ <span class="cstat-no" title="statement not covered" > return { kind: 'let', var: mLet[1], inner: translateStatement(mLet[2].trim(), vars) };</span>
1002
+ <span class="cstat-no" title="statement not covered" > }</span>
1003
+ &nbsp;
1004
+ // RETURN { key: $var, ... } — build an object from scope/vars.
1005
+ let mRet = /^RETURN\s+\{([\s\S]+)\}$/i.exec(s);
1006
+ if (mRet) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
1007
+ <span class="cstat-no" title="statement not covered" > const entries = splitTopLevel(mRet[1], ',').map((pair) =&gt; {</span>
1008
+ <span class="cstat-no" title="statement not covered" > const c = pair.indexOf(':');</span>
1009
+ <span class="cstat-no" title="statement not covered" > const key = pair.slice(0, c).trim();</span>
1010
+ <span class="cstat-no" title="statement not covered" > const v = pair.slice(c + 1).trim();</span>
1011
+ <span class="cstat-no" title="statement not covered" > return { key, var: v.startsWith('$') ? v.slice(1) : v };</span>
1012
+ <span class="cstat-no" title="statement not covered" > });</span>
1013
+ <span class="cstat-no" title="statement not covered" > return { kind: 'return', entries };</span>
1014
+ <span class="cstat-no" title="statement not covered" > }</span>
1015
+ &nbsp;
1016
+ // `INFO FOR DB` is the ONE INFO statement with a real answer here: the
1017
+ // DevTools Database explorer enumerates tables with it. Answered from
1018
+ // `sqlite_master` (see the engine) instead of being swallowed by the DDL
1019
+ // noop below, which left the explorer with an empty table list.
1020
+ if (/^INFO\s+FOR\s+DB(\s+STRUCTURE)?$/i.test(s)) return { kind: 'infoForDb' };
1021
+ &nbsp;
1022
+ // ---- schema / session DDL: no-ops on a schemaless engine --------------
1023
+ // SQLite creates tables lazily and has no namespaces/DB DDL, so DEFINE /
1024
+ // REMOVE / USE / INFO / RETURN statements are safely ignored.
1025
+ if (/^(DEFINE|REMOVE|USE|INFO|RETURN|CANCEL|COMMIT|BEGIN)\b/i.test(s)) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
1026
+ <span class="cstat-no" title="statement not covered" > return { kind: 'noop' };</span>
1027
+ <span class="cstat-no" title="statement not covered" > }</span>
1028
+ &nbsp;
1029
+ // ---- writes -----------------------------------------------------------
1030
+ let m =
1031
+ /^CREATE\s+ONLY\s+\$(\w+)\s+CONTENT\s+\$(\w+)$/i.exec(s) ||
1032
+ /^UPSERT\s+ONLY\s+\$(\w+)\s+REPLACE\s+\$(\w+)$/i.exec(s);
1033
+ if (m) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
1034
+ <span class="cstat-no" title="statement not covered" > return { kind: 'upsert', id: rid(vars[m[1]]), data: asRow(vars[m[2]]), mode: 'replace' };</span>
1035
+ <span class="cstat-no" title="statement not covered" > }</span>
1036
+ &nbsp;
1037
+ // The `ONLY` variants come from `surql`; the bare `UPDATE &lt;id&gt; MERGE $x` form
1038
+ // (with a LITERAL record id) is what the DevTools row editor emits.
1039
+ m =
1040
+ idRe(String.raw`^UPSERT\s+ONLY\s+%ID%\s+MERGE\s+\$(\w+)$`).exec(s) ||
1041
+ idRe(String.raw`^UPDATE\s+(?:ONLY\s+)?%ID%\s+MERGE\s+\$(\w+)$`).exec(s);
1042
+ if (m) {
1043
+ return { kind: 'upsert', id: idOperand(m[1], vars), data: asRow(vars[m[2]]), mode: 'merge' };
1044
+ }
1045
+ &nbsp;
1046
+ // CREATE ONLY $id SET a = ..., b = ... (createSet / createMutation)
1047
+ m = /^CREATE\s+ONLY\s+\$(\w+)\s+SET\s+(.+)$/i.exec(s);
1048
+ if (m) {
1049
+ const data: Row = {};
1050
+ for (const { path, value } of parseSetClauses(m[2], vars)) setPath(data, path, value);
1051
+ return { kind: 'upsert', id: rid(vars[m[1]]), data, mode: 'replace' };
1052
+ }
1053
+ &nbsp;
1054
+ // UPDATE $id SET a.b = $x, c = $y [RETURN NONE]
1055
+ m = idRe(String.raw`^UPDATE\s+%ID%\s+SET\s+(.+?)(\s+RETURN\s+NONE)?$`).exec(s);
1056
+ if (m) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
1057
+ <span class="cstat-no" title="statement not covered" > return {</span>
1058
+ <span class="cstat-no" title="statement not covered" > kind: 'updateSet',</span>
1059
+ <span class="cstat-no" title="statement not covered" > id: idOperand(m[1], vars),</span>
1060
+ <span class="cstat-no" title="statement not covered" > sets: parseSetClauses(m[2], vars),</span>
1061
+ <span class="cstat-no" title="statement not covered" > returnNone: !!m[3],</span>
1062
+ <span class="cstat-no" title="statement not covered" > };</span>
1063
+ <span class="cstat-no" title="statement not covered" > }</span>
1064
+ &nbsp;
1065
+ m = /^DELETE\s+([A-Za-z_]\w*)$/i.exec(s); // DELETE &lt;table&gt; (no `:` — a table)
1066
+ if (m) return { kind: 'deleteAll', table: m[1] };
1067
+ &nbsp;
1068
+ // DELETE $id, and `DELETE &lt;table&gt;:&lt;id&gt;` from the DevTools row actions.
1069
+ m = idRe(String.raw`^DELETE\s+%ID%$`).exec(s);
1070
+ if (m) return { kind: 'delete', id: idOperand(m[1], vars) };
1071
+ &nbsp;
1072
+ // ---- reads ------------------------------------------------------------
1073
+ // The paging tail (`LIMIT n [START m]`) is peeled off first so it can't be
1074
+ // swallowed by the lazily-matched WHERE/ORDER BY groups below. Everything
1075
+ // after this point sees a window-free statement.
1076
+ const { head, limit, start } = peelWindow(s, vars);
1077
+ &nbsp;
1078
+ // SELECT count() FROM &lt;table&gt; [WHERE ...] GROUP ALL — the row-count query the
1079
+ // DevTools Database explorer pages with. GROUP ALL is required: without it
1080
+ // SurrealDB counts per row, which is a different result this can't fake.
1081
+ m = /^SELECT\s+count\(\)\s+FROM\s+([A-Za-z_]\w*)(?:\s+WHERE\s+(.+?))?\s+GROUP\s+ALL$/i.exec(head);
1082
+ if (m) {
1083
+ return { kind: 'count', table: m[1], where: m[2] ? parseWhere(m[2], vars) : undefined };
1084
+ }
1085
+ &nbsp;
1086
+ // SELECT [VALUE] &lt;proj&gt; FROM ONLY &lt;id&gt;
1087
+ m = idRe(String.raw`^SELECT\s+(VALUE\s+)?(.+?)\s+FROM\s+ONLY\s+%ID%$`).exec(head);
1088
+ if (m) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
1089
+ <span class="cstat-no" title="statement not covered" > const value = m[1] ? m[2].trim() : undefined;</span>
1090
+ <span class="cstat-no" title="statement not covered" > return { kind: 'getById', id: idOperand(m[3], vars), select: projFields(m[2], !!m[1]), value };</span>
1091
+ <span class="cstat-no" title="statement not covered" > }</span>
1092
+ &nbsp;
1093
+ // SELECT [VALUE] &lt;proj&gt; FROM $arrayParam
1094
+ m = /^SELECT\s+(VALUE\s+)?(.+?)\s+FROM\s+\$(\w+)$/i.exec(head);
1095
+ if (m) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
1096
+ <span class="cstat-no" title="statement not covered" > const value = m[1] ? m[2].trim() : undefined;</span>
1097
+ <span class="cstat-no" title="statement not covered" > return {</span>
1098
+ <span class="cstat-no" title="statement not covered" > kind: 'selectByIds',</span>
1099
+ <span class="cstat-no" title="statement not covered" > ids: (vars[m[3]] as unknown[]) ?? [],</span>
1100
+ <span class="cstat-no" title="statement not covered" > select: projFields(m[2], !!m[1]),</span>
1101
+ <span class="cstat-no" title="statement not covered" > value,</span>
1102
+ <span class="cstat-no" title="statement not covered" > limit,</span>
1103
+ <span class="cstat-no" title="statement not covered" > start,</span>
1104
+ <span class="cstat-no" title="statement not covered" > };</span>
1105
+ <span class="cstat-no" title="statement not covered" > }</span>
1106
+ &nbsp;
1107
+ // SELECT &lt;proj&gt; FROM &lt;table&gt; [WHERE ...] [ORDER BY ...]
1108
+ m =
1109
+ /^SELECT\s+(VALUE\s+)?(.+?)\s+FROM\s+([A-Za-z_]\w*)(?:\s+WHERE\s+(.+?))?(?:\s+ORDER\s+BY\s+(.+?))?$/i.exec(
1110
+ head
1111
+ );
1112
+ if (m) {
1113
+ return {
1114
+ kind: 'selectTable',
1115
+ table: m[3],
1116
+ where: m[4] ? parseWhere(m[4], vars) : undefined,
1117
+ orderBy: m[5] ? parseOrderBy(m[5]) : undefined,
1118
+ select: projFields(m[2], !!m[1]),
1119
+ value: m[1<span class="branch-0 cbranch-no" title="branch not covered" >] ? m[2].trim() : u</span>ndefined,
1120
+ limit,
1121
+ start,
1122
+ };
1123
+ }
1124
+ &nbsp;
1125
+ throw new Error(`SqliteCacheEngine: unsupported SurrealQL for translation: ${stmt}`);
1126
+ }
1127
+ &nbsp;
1128
+ // ==================== clause parsers ====================
1129
+ &nbsp;
1130
+ /**
1131
+ * Split a SELECT's trailing `LIMIT n [START m]` off its head.
1132
+ *
1133
+ * Peeled rather than folded into the SELECT regexes because those match WHERE
1134
+ * and ORDER BY lazily: with the window left in place the WHERE group happily
1135
+ * expands over `… LIMIT 20`, which is how `SELECT * FROM t LIMIT 20 START 0`
1136
+ * ended up unmatched entirely.
1137
+ *
1138
+ * A tail sitting inside a string literal (`WHERE note = 'LIMIT 5'`) is left
1139
+ * alone — an odd quote count in the head means the match is inside a string.
1140
+ */
1141
+ function peelWindow(
1142
+ stmt: string,
1143
+ vars: Record&lt;string, unknown&gt;
1144
+ ): { head: string; limit?: number; start?: number } {
1145
+ let head = stmt;
1146
+ let limit: number | undefined;
1147
+ let start: number | undefined;
1148
+ &nbsp;
1149
+ const peel = (re: RegExp): string | undefined =&gt; {
1150
+ const m = re.exec(head);
1151
+ if (!m) return undefined;
1152
+ const before = head.slice(0, m.index);
1153
+ if (countQuotes(before) % 2 !== 0) <span class="branch-0 cbranch-no" title="branch not covered" >return undefined;</span>
1154
+ head = before;
1155
+ return m[1];
1156
+ };
1157
+ &nbsp;
1158
+ // START is the outer token, so it comes off first.
1159
+ const startTok = peel(/\s+START(?:\s+AT)?\s+(\$?\w+)\s*$/i);
1160
+ const limitTok = peel(/\s+LIMIT(?:\s+BY)?\s+(\$?\w+)\s*$/i);
1161
+ if (startTok !== undefined) start = numOperand(startTok, vars);
1162
+ if (limitTok !== undefined) limit = numOperand(limitTok, vars);
1163
+ return { head, limit, start };
1164
+ }
1165
+ &nbsp;
1166
+ function countQuotes(s: string): number {
1167
+ let n = 0;
1168
+ for (let i = 0; i &lt; s.length; i++) {
1169
+ if (s[i] === <span class="branch-0 cbranch-no" title="branch not covered" >"'" &amp;&amp; s[i - 1] !== '\\') <span class="branch-0 cbranch-no" title="branch not covered" >n</span>++;</span>
1170
+ }
1171
+ return n;
1172
+ }
1173
+ &nbsp;
1174
+ /** A `LIMIT`/`START` operand: a literal integer or a `$var` holding one. */
1175
+ function numOperand(token: string, vars: Record&lt;string, unknown&gt;): number | undefined {
1176
+ const raw = token.startsWith('$'<span class="branch-0 cbranch-no" title="branch not covered" >) ? vars[token.slice(1)] : t</span>oken;
1177
+ const n = Number(raw);
1178
+ return Number.isFinite(n) ? <span class="branch-0 cbranch-no" title="branch not covered" >n : undefined;</span>
1179
+ }
1180
+ &nbsp;
1181
+ /**
1182
+ * A single-record operand: `$var` or a LITERAL `table:id`.
1183
+ *
1184
+ * A bare identifier deliberately does NOT match: in SurrealQL that is a table,
1185
+ * and `UPDATE game MERGE $x` rewrites every row of `game` — a shape this
1186
+ * vocabulary does not implement. Not matching means such a statement reaches
1187
+ * the "unsupported SurrealQL" throw instead of quietly writing one row called
1188
+ * `game`.
1189
+ */
1190
+ const ID_TOKEN = String.raw`(\$\w+|[A-Za-z_]\w*:\S+)`;
1191
+ &nbsp;
1192
+ /** Build a statement regex, `%ID%` expanding to {@link ID_TOKEN}. */
1193
+ function idRe(pattern: string): RegExp {
1194
+ return new RegExp(pattern.replace('%ID%', ID_TOKEN), 'i');
1195
+ }
1196
+ &nbsp;
1197
+ /**
1198
+ * Resolve an {@link ID_TOKEN} match. Literals matter because the DevTools row
1199
+ * editor inlines the id (`UPDATE game:abc MERGE $updates`) rather than binding
1200
+ * it; `stableKey` treats that string and a `RecordId` identically downstream.
1201
+ */
1202
+ function idOperand(token: string, vars: Record&lt;string, unknown&gt;): unknown {
1203
+ const t = token.trim();
1204
+ return t.startsWith('$'<span class="branch-0 cbranch-no" title="branch not covered" >) ? rid(vars[t.slice(1)]) : t</span>;
1205
+ }
1206
+ &nbsp;
1207
+ function projFields(proj: string, isValue: boolean): string[] | undefined {
1208
+ const p = proj.trim();
1209
+ if (isValue) <span class="branch-0 cbranch-no" title="branch not covered" >return undefined; // VALUE returns a scalar, no projection object</span>
1210
+ if (p === '*') return <span class="branch-0 cbranch-no" title="branch not covered" >undefined;</span>
1211
+ <span class="cstat-no" title="statement not covered" > return p.split(',').map((f) =&gt; f.trim());</span>
1212
+ <span class="cstat-no" title="statement not covered" >}</span>
1213
+ &nbsp;
1214
+ function asRow(v: unknown): Row {
1215
+ return (v &amp;&amp; typeof v === 'object' ? <span class="branch-0 cbranch-no" title="branch not covered" >v : {}) as Row;</span>
1216
+ }
1217
+ &nbsp;
1218
+ /** Parse `a = $x, b.c = 'lit', _00_rv += 1` into path/op/value triples. */
1219
+ function parseSetClauses(clause: string, vars: Record&lt;string, unknown&gt;): SetClause[] {
1220
+ return splitTopLevel(clause, ',').map((part) =&gt; {
1221
+ const m = /^(.+?)\s*(\+=|-=|=)\s*([\s\S]+)$/.exec(part.trim());
1222
+ if (!m) <span class="branch-0 cbranch-no" title="branch not covered" >throw new Error(`SqliteCacheEngine: cannot parse SET clause: ${part}`);</span>
1223
+ return { path: m[1].trim(), op: m[2] as SetClause['op'], value: literalOrVar(m[3], vars) };
1224
+ });
1225
+ }
1226
+ &nbsp;
1227
+ function literalOrVar(token: string, vars: Record&lt;string, unknown&gt;): unknown {
1228
+ const t = token.trim();
1229
+ if (t.startsWith('$')) return vars[t.slice(1)];
1230
+ if (/^'.*'$/.test(t) || /^".*"$/.test(t)) return t.slice(1, -1);
1231
+ if (/^-?\d+(\.\d+)?$/.test(t)) <span class="branch-0 cbranch-no" title="branch not covered" >return Number(t);</span>
1232
+ if (t === 'true') return <span class="branch-0 cbranch-no" title="branch not covered" >true;</span>
1233
+ <span class="cstat-no" title="statement not covered" > if (t === 'false') return false;</span>
1234
+ if (t === 'NONE' || t === <span class="branch-0 cbranch-no" title="branch not covered" >'NULL' || t === 'null') <span class="branch-0 cbranch-no" title="branch not covered" >r</span>eturn null;</span>
1235
+ <span class="cstat-no" title="statement not covered" > return t;</span>
1236
+ <span class="cstat-no" title="statement not covered" >}</span>
1237
+ &nbsp;
1238
+ function parseWhere(clause: string, vars: Record&lt;string, unknown&gt;): WhereNode[] {
1239
+ // Only simple AND-of-equality/comparison is emitted by the client's raw
1240
+ // queries; OR/nested go through plan-based select().
1241
+ return splitTopLevel(clause, 'AND').map((cond) =&gt; {
1242
+ const m = /^(\S+)\s*(=|!=|&gt;=|&lt;=|&gt;|&lt;)\s*(.+)$/.exec(cond.trim());
1243
+ if (!m) <span class="branch-0 cbranch-no" title="branch not covered" >throw new Error(`SqliteCacheEngine: cannot parse WHERE condition: ${cond}`);</span>
1244
+ return { field: m[1], op: m[2] as WhereComparisonOp, value: literalOrVar(m[3], vars) };
1245
+ });
1246
+ }
1247
+ &nbsp;
1248
+ type WhereComparisonOp = '=' | '!=' | '&gt;=' | '&lt;=' | '&gt;' | '&lt;';
1249
+ &nbsp;
1250
+ function parseOrderBy(clause: string): OrderBy {
1251
+ return clause.split(',').map((c) =&gt; {
1252
+ const [f, dir] = c.trim().split(/\s+/);
1253
+ return [f, (<span class="branch-0 cbranch-no" title="branch not covered" >dir ?? 'asc').t</span>oLowerCase() === 'desc' ? <span class="branch-0 cbranch-no" title="branch not covered" >'desc' : 'asc']</span>;
1254
+ });
1255
+ }
1256
+ &nbsp;
1257
+ /** Split on a top-level separator, ignoring parens/quotes (bounded inputs). */
1258
+ function splitTopLevel(input: string, sep: string): string[] {
1259
+ const out: string[] = [];
1260
+ let depth = 0;
1261
+ let inStr: string | null = null;
1262
+ let cur = '';
1263
+ const isWord = /[A-Za-z]/.test(sep);
1264
+ for (let i = 0; i &lt; input.length; i++) {
1265
+ const ch = input[i];
1266
+ if (inStr) {
1267
+ cur += ch;
1268
+ if (ch === inStr) inStr = null;
1269
+ continue;
1270
+ }
1271
+ if (ch === "'" || ch === '"') {
1272
+ inStr = ch;
1273
+ cur += ch;
1274
+ continue;
1275
+ }
1276
+ if (ch === '(') <span class="branch-0 cbranch-no" title="branch not covered" >depth++;</span>
1277
+ if (ch === ')') <span class="branch-0 cbranch-no" title="branch not covered" >depth--;</span>
1278
+ const matches = isWord
1279
+ ? depth === 0 &amp;&amp; input.slice(i, i + sep.length).toUpperCase() === <span class="branch-0 cbranch-no" title="branch not covered" >sep &amp;&amp; /\s/.test(input[i - 1] ?? ' ')</span>
1280
+ : depth === 0 &amp;&amp; ch === sep;
1281
+ if (matches) {
1282
+ out.push(cur.trim());
1283
+ cur = '';
1284
+ i += sep.length - 1;
1285
+ continue;
1286
+ }
1287
+ cur += ch;
1288
+ }
1289
+ if (cur.trim()) out.push(cur.trim());
1290
+ return out;
1291
+ }
1292
+ &nbsp;
1293
+ /** Read a possibly-dotted path (`a.b.c`) from an object. */
1294
+ export <span class="fstat-no" title="function not covered" >function getPath(obj: Row, path: string): unknown {</span>
1295
+ <span class="cstat-no" title="statement not covered" > let cur: unknown = obj;</span>
1296
+ <span class="cstat-no" title="statement not covered" > for (const k of path.split('.')) {</span>
1297
+ <span class="cstat-no" title="statement not covered" > if (cur == null || typeof cur !== 'object') return undefined;</span>
1298
+ <span class="cstat-no" title="statement not covered" > cur = (cur as Row)[k];</span>
1299
+ <span class="cstat-no" title="statement not covered" > }</span>
1300
+ <span class="cstat-no" title="statement not covered" > return cur;</span>
1301
+ <span class="cstat-no" title="statement not covered" >}</span>
1302
+ &nbsp;
1303
+ /** Set a possibly-dotted path (`a.b.c`) on an object. */
1304
+ export function setPath(obj: Row, path: string, value: unknown): void {
1305
+ const parts = path.split('.');
1306
+ let cur: Row = obj;
1307
+ for (let i = 0; i &lt; parts.length - 1; i++) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
1308
+ <span class="cstat-no" title="statement not covered" > const k = parts[i];</span>
1309
+ <span class="cstat-no" title="statement not covered" > if (typeof cur[k] !== 'object' || cur[k] === null) cur[k] = {};</span>
1310
+ <span class="cstat-no" title="statement not covered" > cur = cur[k] as Row;</span>
1311
+ <span class="cstat-no" title="statement not covered" > }</span>
1312
+ cur[parts[parts.length - 1]] = value;
1313
+ }
1314
+ &nbsp;</pre></td></tr></table></pre>
1315
+
1316
+ <div class='push'></div><!-- for sticky footer -->
1317
+ </div><!-- /wrapper -->
1318
+ <div class='footer quiet pad2 space-top1 center small'>
1319
+ Code coverage generated by
1320
+ <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
1321
+ at 2026-09-09T09:49:51.780Z
1322
+ </div>
1323
+ <script src="../../../prettify.js"></script>
1324
+ <script>
1325
+ window.onload = function () {
1326
+ prettyPrint();
1327
+ };
1328
+ </script>
1329
+ <script src="../../../sorter.js"></script>
1330
+ <script src="../../../block-navigation.js"></script>
1331
+ </body>
1332
+ </html>
1333
+