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

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 (292) hide show
  1. package/AGENTS.md +34 -15
  2. package/README.md +56 -16
  3. package/dist/index.d.ts +1136 -1846
  4. package/dist/index.js +10168 -11267
  5. package/dist/sqlite-open.js +10 -1
  6. package/dist/types.d.ts +22 -79
  7. package/package.json +8 -4
  8. package/skills/sp00ky-core/SKILL.md +18 -0
  9. package/src/boot/auth-flip.saga.test.ts +82 -0
  10. package/src/boot/auth-flip.saga.ts +62 -0
  11. package/src/boot/boot.saga.test.ts +151 -0
  12. package/src/boot/boot.saga.ts +128 -0
  13. package/src/boot/bucket-switch.saga.test.ts +158 -0
  14. package/src/boot/bucket-switch.saga.ts +115 -0
  15. package/src/boot/preload.saga.test.ts +51 -0
  16. package/src/boot/preload.saga.ts +31 -0
  17. package/src/client/bucket-handle.test.ts +117 -0
  18. package/src/client/bucket-handle.ts +227 -0
  19. package/src/client/router.test.ts +56 -0
  20. package/src/client/router.ts +94 -0
  21. package/src/client/runtime.test.ts +192 -0
  22. package/src/client/runtime.ts +296 -0
  23. package/src/client/services.ts +349 -0
  24. package/src/client/sp00ky-client.test.ts +241 -0
  25. package/src/client/sp00ky-client.ts +482 -0
  26. package/src/index.ts +1 -0
  27. package/src/kernel/constants.test.ts +19 -0
  28. package/src/kernel/constants.ts +54 -0
  29. package/src/kernel/effects.test.ts +40 -0
  30. package/src/kernel/effects.ts +159 -0
  31. package/src/kernel/events.ts +55 -0
  32. package/src/kernel/interpreter.test.ts +116 -0
  33. package/src/kernel/interpreter.ts +143 -0
  34. package/src/kernel/saga.test.ts +89 -0
  35. package/src/kernel/saga.ts +73 -0
  36. package/src/modules/app-release/index.ts +13 -5
  37. package/src/modules/devtools/index.ts +10 -3
  38. package/src/modules/devtools/state-shape.test.ts +4 -1
  39. package/src/modules/feature-flag/index.ts +13 -5
  40. package/src/mutation/jobs.test.ts +25 -0
  41. package/src/mutation/jobs.ts +41 -0
  42. package/src/{modules/data → mutation}/mutation-id.test.ts +12 -0
  43. package/src/mutation/push.saga.test.ts +285 -0
  44. package/src/mutation/push.saga.ts +215 -0
  45. package/src/mutation/rows.test.ts +201 -0
  46. package/src/mutation/rows.ts +377 -0
  47. package/src/mutation/tray.saga.test.ts +63 -0
  48. package/src/mutation/tray.saga.ts +48 -0
  49. package/src/mutation/write.saga.test.ts +163 -0
  50. package/src/mutation/write.saga.ts +166 -0
  51. package/src/query/env.test.ts +23 -0
  52. package/src/query/env.ts +56 -0
  53. package/src/query/fetch.saga.test.ts +156 -0
  54. package/src/query/fetch.saga.ts +109 -0
  55. package/src/query/hash.test.ts +14 -0
  56. package/src/query/hash.ts +18 -0
  57. package/src/{modules/data → query}/id-set-plan.test.ts +12 -2
  58. package/src/query/lifecycle.saga.test.ts +122 -0
  59. package/src/query/lifecycle.saga.ts +101 -0
  60. package/src/query/materialize.saga.test.ts +82 -0
  61. package/src/query/materialize.saga.ts +75 -0
  62. package/src/query/materialize.test.ts +50 -0
  63. package/src/query/materialize.ts +44 -0
  64. package/src/query/membership.saga.test.ts +246 -0
  65. package/src/query/membership.saga.ts +208 -0
  66. package/src/query/membership.test.ts +118 -0
  67. package/src/query/membership.ts +158 -0
  68. package/src/query/register.saga.test.ts +251 -0
  69. package/src/query/register.saga.ts +190 -0
  70. package/src/query/render-set.test.ts +36 -0
  71. package/src/query/render-set.ts +60 -0
  72. package/src/query/sql.test.ts +62 -0
  73. package/src/query/sql.ts +79 -0
  74. package/src/{modules/data → query}/window-query.test.ts +18 -0
  75. package/src/{modules/data → query}/window-query.ts +2 -1
  76. package/src/services/database/connection-supervisor.test.ts +29 -0
  77. package/src/services/database/connection-supervisor.ts +7 -0
  78. package/src/services/database/database.responses.test.ts +43 -0
  79. package/src/services/database/database.ts +25 -10
  80. package/src/services/database/local-migrator.ts +2 -2
  81. package/src/services/database/plan-render.test.ts +1 -1
  82. package/src/services/database/sqlite-cache-engine.test.ts +4 -3
  83. package/src/services/database/sqlite-cache-engine.ts +2 -11
  84. package/src/services/database/sqlite-devtools-queries.integration.test.ts +1 -1
  85. package/src/services/database/sqlite-plan-sql.ts +16 -1
  86. package/src/services/database/sqlite-projection.test.ts +25 -3
  87. package/src/services/tabs/protocol.ts +7 -3
  88. package/src/sp00ky.ts +5 -1854
  89. package/src/state/client-state.ts +184 -0
  90. package/src/state/lifecycle.test.ts +118 -0
  91. package/src/state/lifecycle.ts +86 -0
  92. package/src/state/reducers.test.ts +280 -0
  93. package/src/state/reducers.ts +476 -0
  94. package/src/state/selectors.test.ts +149 -0
  95. package/src/state/selectors.ts +184 -0
  96. package/src/sync/connection.saga.test.ts +86 -0
  97. package/src/sync/connection.saga.ts +85 -0
  98. package/src/sync/live.saga.test.ts +69 -0
  99. package/src/sync/live.saga.ts +49 -0
  100. package/src/sync/policy.health.test.ts +56 -0
  101. package/src/{modules/sync/utils.test.ts → sync/policy.test.ts} +31 -3
  102. package/src/{modules/sync/utils.ts → sync/policy.ts} +67 -5
  103. package/src/sync/poll.saga.test.ts +51 -0
  104. package/src/sync/poll.saga.ts +36 -0
  105. package/src/sync/tabs.saga.test.ts +74 -0
  106. package/src/sync/tabs.saga.ts +92 -0
  107. package/src/testing/adapters.ts +133 -0
  108. package/src/testing/build.ts +61 -0
  109. package/src/testing/fake-services.ts +34 -0
  110. package/src/testing/run-pure.test.ts +92 -0
  111. package/src/testing/run-pure.ts +128 -0
  112. package/src/testing/services.ts +17 -0
  113. package/src/types.ts +8 -7
  114. package/src/utils/utils.test.ts +2 -1
  115. package/vitest.config.ts +48 -0
  116. package/coverage/lcov-report/base.css +0 -224
  117. package/coverage/lcov-report/block-navigation.js +0 -87
  118. package/coverage/lcov-report/favicon.png +0 -0
  119. package/coverage/lcov-report/index.html +0 -476
  120. package/coverage/lcov-report/prettify.css +0 -1
  121. package/coverage/lcov-report/prettify.js +0 -2
  122. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  123. package/coverage/lcov-report/sorter.js +0 -210
  124. package/coverage/lcov-report/src/boot/auth-flip.saga.ts.html +0 -271
  125. package/coverage/lcov-report/src/boot/boot.saga.ts.html +0 -469
  126. package/coverage/lcov-report/src/boot/bucket-switch.saga.ts.html +0 -430
  127. package/coverage/lcov-report/src/boot/index.html +0 -161
  128. package/coverage/lcov-report/src/boot/preload.saga.ts.html +0 -178
  129. package/coverage/lcov-report/src/client/bucket-handle.ts.html +0 -766
  130. package/coverage/lcov-report/src/client/index.html +0 -161
  131. package/coverage/lcov-report/src/client/router.ts.html +0 -367
  132. package/coverage/lcov-report/src/client/runtime.ts.html +0 -940
  133. package/coverage/lcov-report/src/client/sp00ky-client.ts.html +0 -1531
  134. package/coverage/lcov-report/src/events/index.html +0 -116
  135. package/coverage/lcov-report/src/events/index.ts.html +0 -877
  136. package/coverage/lcov-report/src/index.html +0 -146
  137. package/coverage/lcov-report/src/index.ts.html +0 -202
  138. package/coverage/lcov-report/src/kernel/constants.ts.html +0 -247
  139. package/coverage/lcov-report/src/kernel/effects.ts.html +0 -562
  140. package/coverage/lcov-report/src/kernel/events.ts.html +0 -250
  141. package/coverage/lcov-report/src/kernel/index.html +0 -176
  142. package/coverage/lcov-report/src/kernel/interpreter.ts.html +0 -514
  143. package/coverage/lcov-report/src/kernel/saga.ts.html +0 -304
  144. package/coverage/lcov-report/src/modules/app-release/index.html +0 -116
  145. package/coverage/lcov-report/src/modules/app-release/index.ts.html +0 -712
  146. package/coverage/lcov-report/src/modules/auth/events/index.html +0 -116
  147. package/coverage/lcov-report/src/modules/auth/events/index.ts.html +0 -142
  148. package/coverage/lcov-report/src/modules/auth/index.html +0 -116
  149. package/coverage/lcov-report/src/modules/auth/index.ts.html +0 -1225
  150. package/coverage/lcov-report/src/modules/crdt/crdt-field.ts.html +0 -967
  151. package/coverage/lcov-report/src/modules/crdt/index.html +0 -146
  152. package/coverage/lcov-report/src/modules/crdt/index.ts.html +0 -1474
  153. package/coverage/lcov-report/src/modules/crdt/loro-loader.ts.html +0 -160
  154. package/coverage/lcov-report/src/modules/devtools/flags.ts.html +0 -1132
  155. package/coverage/lcov-report/src/modules/devtools/index.html +0 -161
  156. package/coverage/lcov-report/src/modules/devtools/index.ts.html +0 -2413
  157. package/coverage/lcov-report/src/modules/devtools/storage-info.ts.html +0 -589
  158. package/coverage/lcov-report/src/modules/devtools/versions.ts.html +0 -415
  159. package/coverage/lcov-report/src/modules/feature-flag/index.html +0 -116
  160. package/coverage/lcov-report/src/modules/feature-flag/index.ts.html +0 -1033
  161. package/coverage/lcov-report/src/modules/index.html +0 -116
  162. package/coverage/lcov-report/src/modules/ref-tables.ts.html +0 -349
  163. package/coverage/lcov-report/src/mutation/index.html +0 -191
  164. package/coverage/lcov-report/src/mutation/jobs.ts.html +0 -208
  165. package/coverage/lcov-report/src/mutation/mutation-id.ts.html +0 -190
  166. package/coverage/lcov-report/src/mutation/push.saga.ts.html +0 -730
  167. package/coverage/lcov-report/src/mutation/rows.ts.html +0 -1216
  168. package/coverage/lcov-report/src/mutation/tray.saga.ts.html +0 -229
  169. package/coverage/lcov-report/src/mutation/write.saga.ts.html +0 -583
  170. package/coverage/lcov-report/src/otel/index.html +0 -116
  171. package/coverage/lcov-report/src/otel/index.ts.html +0 -466
  172. package/coverage/lcov-report/src/query/env.ts.html +0 -253
  173. package/coverage/lcov-report/src/query/fetch.saga.ts.html +0 -412
  174. package/coverage/lcov-report/src/query/hash.ts.html +0 -139
  175. package/coverage/lcov-report/src/query/index.html +0 -281
  176. package/coverage/lcov-report/src/query/lifecycle.saga.ts.html +0 -388
  177. package/coverage/lcov-report/src/query/materialize.saga.ts.html +0 -310
  178. package/coverage/lcov-report/src/query/materialize.ts.html +0 -217
  179. package/coverage/lcov-report/src/query/membership.saga.ts.html +0 -709
  180. package/coverage/lcov-report/src/query/membership.ts.html +0 -559
  181. package/coverage/lcov-report/src/query/register.saga.ts.html +0 -655
  182. package/coverage/lcov-report/src/query/render-set.ts.html +0 -265
  183. package/coverage/lcov-report/src/query/sql.ts.html +0 -322
  184. package/coverage/lcov-report/src/query/window-query.ts.html +0 -670
  185. package/coverage/lcov-report/src/services/blobs/blob-cache.ts.html +0 -1894
  186. package/coverage/lcov-report/src/services/blobs/blob-manifest.ts.html +0 -766
  187. package/coverage/lcov-report/src/services/blobs/blob-store.ts.html +0 -1162
  188. package/coverage/lcov-report/src/services/blobs/index.html +0 -161
  189. package/coverage/lcov-report/src/services/blobs/index.ts.html +0 -295
  190. package/coverage/lcov-report/src/services/database/cache-engine.ts.html +0 -664
  191. package/coverage/lcov-report/src/services/database/connection-supervisor.ts.html +0 -1330
  192. package/coverage/lcov-report/src/services/database/database.ts.html +0 -658
  193. package/coverage/lcov-report/src/services/database/engine-factory.ts.html +0 -184
  194. package/coverage/lcov-report/src/services/database/errors.ts.html +0 -187
  195. package/coverage/lcov-report/src/services/database/events/index.html +0 -116
  196. package/coverage/lcov-report/src/services/database/events/index.ts.html +0 -184
  197. package/coverage/lcov-report/src/services/database/index.html +0 -386
  198. package/coverage/lcov-report/src/services/database/index.ts.html +0 -121
  199. package/coverage/lcov-report/src/services/database/local-migrator.ts.html +0 -703
  200. package/coverage/lcov-report/src/services/database/local.ts.html +0 -1633
  201. package/coverage/lcov-report/src/services/database/plan-render.ts.html +0 -409
  202. package/coverage/lcov-report/src/services/database/relation-resolver.ts.html +0 -682
  203. package/coverage/lcov-report/src/services/database/remote.ts.html +0 -1036
  204. package/coverage/lcov-report/src/services/database/sqlite-cache-engine.ts.html +0 -4132
  205. package/coverage/lcov-report/src/services/database/sqlite-lock-verify.ts.html +0 -220
  206. package/coverage/lcov-report/src/services/database/sqlite-open.ts.html +0 -577
  207. package/coverage/lcov-report/src/services/database/sqlite-plan-sql.ts.html +0 -499
  208. package/coverage/lcov-report/src/services/database/sqlite-select.ts.html +0 -478
  209. package/coverage/lcov-report/src/services/database/sqlite-transport.ts.html +0 -757
  210. package/coverage/lcov-report/src/services/database/surql-translate.ts.html +0 -1333
  211. package/coverage/lcov-report/src/services/database/surreal-cache-engine.ts.html +0 -568
  212. package/coverage/lcov-report/src/services/logger/index.html +0 -116
  213. package/coverage/lcov-report/src/services/logger/index.ts.html +0 -154
  214. package/coverage/lcov-report/src/services/persistence/index.html +0 -146
  215. package/coverage/lcov-report/src/services/persistence/localstorage.ts.html +0 -163
  216. package/coverage/lcov-report/src/services/persistence/resilient.ts.html +0 -208
  217. package/coverage/lcov-report/src/services/persistence/surrealdb.ts.html +0 -271
  218. package/coverage/lcov-report/src/services/stream-processor/index.html +0 -146
  219. package/coverage/lcov-report/src/services/stream-processor/index.ts.html +0 -3313
  220. package/coverage/lcov-report/src/services/stream-processor/permissions.ts.html +0 -244
  221. package/coverage/lcov-report/src/services/stream-processor/wasm-types.ts.html +0 -346
  222. package/coverage/lcov-report/src/services/tabs/broker-client.ts.html +0 -934
  223. package/coverage/lcov-report/src/services/tabs/coordinator.ts.html +0 -1984
  224. package/coverage/lcov-report/src/services/tabs/index.html +0 -191
  225. package/coverage/lcov-report/src/services/tabs/leader-locks.ts.html +0 -310
  226. package/coverage/lcov-report/src/services/tabs/protocol.ts.html +0 -871
  227. package/coverage/lcov-report/src/services/tabs/support.ts.html +0 -193
  228. package/coverage/lcov-report/src/services/tabs/tabs-broker-worker.ts.html +0 -2005
  229. package/coverage/lcov-report/src/sp00ky.ts.html +0 -100
  230. package/coverage/lcov-report/src/state/client-state.ts.html +0 -637
  231. package/coverage/lcov-report/src/state/index.html +0 -161
  232. package/coverage/lcov-report/src/state/lifecycle.ts.html +0 -343
  233. package/coverage/lcov-report/src/state/reducers.ts.html +0 -1471
  234. package/coverage/lcov-report/src/state/selectors.ts.html +0 -637
  235. package/coverage/lcov-report/src/sync/connection.saga.ts.html +0 -343
  236. package/coverage/lcov-report/src/sync/index.html +0 -176
  237. package/coverage/lcov-report/src/sync/live.saga.ts.html +0 -232
  238. package/coverage/lcov-report/src/sync/policy.ts.html +0 -1606
  239. package/coverage/lcov-report/src/sync/poll.saga.ts.html +0 -193
  240. package/coverage/lcov-report/src/sync/tabs.saga.ts.html +0 -361
  241. package/coverage/lcov-report/src/types.ts.html +0 -2419
  242. package/coverage/lcov-report/src/utils/blurhash.ts.html +0 -355
  243. package/coverage/lcov-report/src/utils/error-classification.ts.html +0 -244
  244. package/coverage/lcov-report/src/utils/index.html +0 -191
  245. package/coverage/lcov-report/src/utils/index.ts.html +0 -820
  246. package/coverage/lcov-report/src/utils/parser.ts.html +0 -313
  247. package/coverage/lcov-report/src/utils/semver.ts.html +0 -175
  248. package/coverage/lcov-report/src/utils/surql.ts.html +0 -667
  249. package/coverage/lcov.info +0 -19079
  250. package/src/modules/cache/cache.relay.test.ts +0 -95
  251. package/src/modules/cache/index.ts +0 -361
  252. package/src/modules/cache/types.ts +0 -19
  253. package/src/modules/data/data.activity.test.ts +0 -109
  254. package/src/modules/data/data.authority.test.ts +0 -122
  255. package/src/modules/data/data.heartbeat-wake.test.ts +0 -115
  256. package/src/modules/data/data.hydration.test.ts +0 -142
  257. package/src/modules/data/data.membership.test.ts +0 -623
  258. package/src/modules/data/data.notify-table.test.ts +0 -41
  259. package/src/modules/data/data.pending-ids.test.ts +0 -199
  260. package/src/modules/data/data.rebind.test.ts +0 -170
  261. package/src/modules/data/data.rematerialize.test.ts +0 -114
  262. package/src/modules/data/data.run.test.ts +0 -113
  263. package/src/modules/data/data.settled-writes.test.ts +0 -235
  264. package/src/modules/data/data.status.test.ts +0 -249
  265. package/src/modules/data/data.test.ts +0 -58
  266. package/src/modules/data/index.ts +0 -2745
  267. package/src/modules/sync/engine.ts +0 -250
  268. package/src/modules/sync/events/index.ts +0 -84
  269. package/src/modules/sync/index.ts +0 -3
  270. package/src/modules/sync/queue/index.ts +0 -2
  271. package/src/modules/sync/queue/queue-down.test.ts +0 -228
  272. package/src/modules/sync/queue/queue-down.ts +0 -184
  273. package/src/modules/sync/queue/queue-up.forwarded.test.ts +0 -164
  274. package/src/modules/sync/queue/queue-up.ts +0 -407
  275. package/src/modules/sync/scheduler.pause.test.ts +0 -109
  276. package/src/modules/sync/scheduler.retry.test.ts +0 -237
  277. package/src/modules/sync/scheduler.ts +0 -286
  278. package/src/modules/sync/sync.cleanup.test.ts +0 -116
  279. package/src/modules/sync/sync.health.test.ts +0 -167
  280. package/src/modules/sync/sync.heartbeat.test.ts +0 -80
  281. package/src/modules/sync/sync.list-ref-meta.test.ts +0 -193
  282. package/src/modules/sync/sync.live-removal.test.ts +0 -289
  283. package/src/modules/sync/sync.reconnect.test.ts +0 -145
  284. package/src/modules/sync/sync.rematerialize-after-fetch.test.ts +0 -93
  285. package/src/modules/sync/sync.settled-poll.test.ts +0 -58
  286. package/src/modules/sync/sync.subquery.test.ts +0 -82
  287. package/src/modules/sync/sync.tabs.test.ts +0 -249
  288. package/src/modules/sync/sync.ts +0 -2626
  289. package/src/sp00ky.auth-order.test.ts +0 -112
  290. package/src/sp00ky.init-query.test.ts +0 -183
  291. package/src/sp00ky.local-first.test.ts +0 -60
  292. /package/src/{modules/data → mutation}/mutation-id.ts +0 -0
@@ -1,1330 +0,0 @@
1
-
2
- <!doctype html>
3
- <html lang="en">
4
-
5
- <head>
6
- <title>Code coverage report for src/services/database/connection-supervisor.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> connection-supervisor.ts</h1>
23
- <div class='clearfix'>
24
-
25
- <div class='fl pad1y space-right2'>
26
- <span class="strong">92.52% </span>
27
- <span class="quiet">Statements</span>
28
- <span class='fraction'>260/281</span>
29
- </div>
30
-
31
-
32
- <div class='fl pad1y space-right2'>
33
- <span class="strong">76.47% </span>
34
- <span class="quiet">Branches</span>
35
- <span class='fraction'>52/68</span>
36
- </div>
37
-
38
-
39
- <div class='fl pad1y space-right2'>
40
- <span class="strong">94.73% </span>
41
- <span class="quiet">Functions</span>
42
- <span class='fraction'>18/19</span>
43
- </div>
44
-
45
-
46
- <div class='fl pad1y space-right2'>
47
- <span class="strong">92.52% </span>
48
- <span class="quiet">Lines</span>
49
- <span class='fraction'>260/281</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 high'></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></td><td class="line-coverage quiet"><span class="cline-any cline-yes">1x</span>
482
- <span class="cline-any cline-neutral">&nbsp;</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-yes">1x</span>
512
- <span class="cline-any cline-yes">12x</span>
513
- <span class="cline-any cline-yes">12x</span>
514
- <span class="cline-any cline-neutral">&nbsp;</span>
515
- <span class="cline-any cline-yes">12x</span>
516
- <span class="cline-any cline-yes">12x</span>
517
- <span class="cline-any cline-neutral">&nbsp;</span>
518
- <span class="cline-any cline-yes">12x</span>
519
- <span class="cline-any cline-yes">12x</span>
520
- <span class="cline-any cline-neutral">&nbsp;</span>
521
- <span class="cline-any cline-yes">12x</span>
522
- <span class="cline-any cline-yes">12x</span>
523
- <span class="cline-any cline-neutral">&nbsp;</span>
524
- <span class="cline-any cline-yes">12x</span>
525
- <span class="cline-any cline-neutral">&nbsp;</span>
526
- <span class="cline-any cline-yes">12x</span>
527
- <span class="cline-any cline-yes">12x</span>
528
- <span class="cline-any cline-neutral">&nbsp;</span>
529
- <span class="cline-any cline-yes">12x</span>
530
- <span class="cline-any cline-yes">12x</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-yes">12x</span>
536
- <span class="cline-any cline-neutral">&nbsp;</span>
537
- <span class="cline-any cline-yes">12x</span>
538
- <span class="cline-any cline-neutral">&nbsp;</span>
539
- <span class="cline-any cline-yes">12x</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-neutral">&nbsp;</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-neutral">&nbsp;</span>
550
- <span class="cline-any cline-neutral">&nbsp;</span>
551
- <span class="cline-any cline-neutral">&nbsp;</span>
552
- <span class="cline-any cline-yes">12x</span>
553
- <span class="cline-any cline-neutral">&nbsp;</span>
554
- <span class="cline-any cline-yes">12x</span>
555
- <span class="cline-any cline-neutral">&nbsp;</span>
556
- <span class="cline-any cline-yes">12x</span>
557
- <span class="cline-any cline-neutral">&nbsp;</span>
558
- <span class="cline-any cline-yes">12x</span>
559
- <span class="cline-any cline-yes">9x</span>
560
- <span class="cline-any cline-yes">9x</span>
561
- <span class="cline-any cline-yes">9x</span>
562
- <span class="cline-any cline-yes">9x</span>
563
- <span class="cline-any cline-yes">9x</span>
564
- <span class="cline-any cline-yes">9x</span>
565
- <span class="cline-any cline-yes">9x</span>
566
- <span class="cline-any cline-neutral">&nbsp;</span>
567
- <span class="cline-any cline-neutral">&nbsp;</span>
568
- <span class="cline-any cline-yes">12x</span>
569
- <span class="cline-any cline-yes">6x</span>
570
- <span class="cline-any cline-yes">6x</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-neutral">&nbsp;</span>
574
- <span class="cline-any cline-neutral">&nbsp;</span>
575
- <span class="cline-any cline-neutral">&nbsp;</span>
576
- <span class="cline-any cline-yes">12x</span>
577
- <span class="cline-any cline-yes">1x</span>
578
- <span class="cline-any cline-yes">1x</span>
579
- <span class="cline-any cline-yes">1x</span>
580
- <span class="cline-any cline-no">&nbsp;</span>
581
- <span class="cline-any cline-no">&nbsp;</span>
582
- <span class="cline-any cline-yes">1x</span>
583
- <span class="cline-any cline-neutral">&nbsp;</span>
584
- <span class="cline-any cline-neutral">&nbsp;</span>
585
- <span class="cline-any cline-neutral">&nbsp;</span>
586
- <span class="cline-any cline-neutral">&nbsp;</span>
587
- <span class="cline-any cline-neutral">&nbsp;</span>
588
- <span class="cline-any cline-yes">12x</span>
589
- <span class="cline-any cline-yes">9x</span>
590
- <span class="cline-any cline-yes">9x</span>
591
- <span class="cline-any cline-neutral">&nbsp;</span>
592
- <span class="cline-any cline-yes">9x</span>
593
- <span class="cline-any cline-neutral">&nbsp;</span>
594
- <span class="cline-any cline-yes">9x</span>
595
- <span class="cline-any cline-yes">9x</span>
596
- <span class="cline-any cline-yes">9x</span>
597
- <span class="cline-any cline-yes">2x</span>
598
- <span class="cline-any cline-neutral">&nbsp;</span>
599
- <span class="cline-any cline-yes">2x</span>
600
- <span class="cline-any cline-yes">9x</span>
601
- <span class="cline-any cline-yes">9x</span>
602
- <span class="cline-any cline-yes">2x</span>
603
- <span class="cline-any cline-yes">2x</span>
604
- <span class="cline-any cline-yes">2x</span>
605
- <span class="cline-any cline-yes">2x</span>
606
- <span class="cline-any cline-yes">9x</span>
607
- <span class="cline-any cline-yes">9x</span>
608
- <span class="cline-any cline-yes">3x</span>
609
- <span class="cline-any cline-yes">3x</span>
610
- <span class="cline-any cline-neutral">&nbsp;</span>
611
- <span class="cline-any cline-neutral">&nbsp;</span>
612
- <span class="cline-any cline-yes">3x</span>
613
- <span class="cline-any cline-yes">9x</span>
614
- <span class="cline-any cline-yes">9x</span>
615
- <span class="cline-any cline-no">&nbsp;</span>
616
- <span class="cline-any cline-no">&nbsp;</span>
617
- <span class="cline-any cline-no">&nbsp;</span>
618
- <span class="cline-any cline-no">&nbsp;</span>
619
- <span class="cline-any cline-yes">9x</span>
620
- <span class="cline-any cline-yes">9x</span>
621
- <span class="cline-any cline-neutral">&nbsp;</span>
622
- <span class="cline-any cline-yes">9x</span>
623
- <span class="cline-any cline-neutral">&nbsp;</span>
624
- <span class="cline-any cline-yes">9x</span>
625
- <span class="cline-any cline-no">&nbsp;</span>
626
- <span class="cline-any cline-yes">9x</span>
627
- <span class="cline-any cline-neutral">&nbsp;</span>
628
- <span class="cline-any cline-neutral">&nbsp;</span>
629
- <span class="cline-any cline-yes">12x</span>
630
- <span class="cline-any cline-yes">9x</span>
631
- <span class="cline-any cline-yes">9x</span>
632
- <span class="cline-any cline-yes">9x</span>
633
- <span class="cline-any cline-yes">9x</span>
634
- <span class="cline-any cline-yes">9x</span>
635
- <span class="cline-any cline-yes">49x</span>
636
- <span class="cline-any cline-yes">49x</span>
637
- <span class="cline-any cline-yes">49x</span>
638
- <span class="cline-any cline-neutral">&nbsp;</span>
639
- <span class="cline-any cline-no">&nbsp;</span>
640
- <span class="cline-any cline-yes">49x</span>
641
- <span class="cline-any cline-yes">9x</span>
642
- <span class="cline-any cline-yes">9x</span>
643
- <span class="cline-any cline-yes">9x</span>
644
- <span class="cline-any cline-neutral">&nbsp;</span>
645
- <span class="cline-any cline-yes">12x</span>
646
- <span class="cline-any cline-yes">22x</span>
647
- <span class="cline-any cline-yes">19x</span>
648
- <span class="cline-any cline-yes">19x</span>
649
- <span class="cline-any cline-yes">19x</span>
650
- <span class="cline-any cline-yes">19x</span>
651
- <span class="cline-any cline-yes">19x</span>
652
- <span class="cline-any cline-yes">22x</span>
653
- <span class="cline-any cline-yes">2x</span>
654
- <span class="cline-any cline-yes">2x</span>
655
- <span class="cline-any cline-yes">2x</span>
656
- <span class="cline-any cline-no">&nbsp;</span>
657
- <span class="cline-any cline-no">&nbsp;</span>
658
- <span class="cline-any cline-no">&nbsp;</span>
659
- <span class="cline-any cline-no">&nbsp;</span>
660
- <span class="cline-any cline-no">&nbsp;</span>
661
- <span class="cline-any cline-yes">2x</span>
662
- <span class="cline-any cline-yes">22x</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-neutral">&nbsp;</span>
666
- <span class="cline-any cline-yes">12x</span>
667
- <span class="cline-any cline-yes">13x</span>
668
- <span class="cline-any cline-yes">1x</span>
669
- <span class="cline-any cline-yes">1x</span>
670
- <span class="cline-any cline-yes">1x</span>
671
- <span class="cline-any cline-yes">13x</span>
672
- <span class="cline-any cline-neutral">&nbsp;</span>
673
- <span class="cline-any cline-neutral">&nbsp;</span>
674
- <span class="cline-any cline-neutral">&nbsp;</span>
675
- <span class="cline-any cline-neutral">&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">6x</span>
680
- <span class="cline-any cline-yes">6x</span>
681
- <span class="cline-any cline-yes">5x</span>
682
- <span class="cline-any cline-yes">5x</span>
683
- <span class="cline-any cline-yes">5x</span>
684
- <span class="cline-any cline-yes">5x</span>
685
- <span class="cline-any cline-yes">5x</span>
686
- <span class="cline-any cline-yes">4x</span>
687
- <span class="cline-any cline-yes">4x</span>
688
- <span class="cline-any cline-yes">5x</span>
689
- <span class="cline-any cline-yes">6x</span>
690
- <span class="cline-any cline-neutral">&nbsp;</span>
691
- <span class="cline-any cline-yes">12x</span>
692
- <span class="cline-any cline-yes">5x</span>
693
- <span class="cline-any cline-neutral">&nbsp;</span>
694
- <span class="cline-any cline-yes">5x</span>
695
- <span class="cline-any cline-no">&nbsp;</span>
696
- <span class="cline-any cline-no">&nbsp;</span>
697
- <span class="cline-any cline-no">&nbsp;</span>
698
- <span class="cline-any cline-yes">5x</span>
699
- <span class="cline-any cline-yes">5x</span>
700
- <span class="cline-any cline-yes">5x</span>
701
- <span class="cline-any cline-yes">5x</span>
702
- <span class="cline-any cline-yes">5x</span>
703
- <span class="cline-any cline-yes">5x</span>
704
- <span class="cline-any cline-yes">5x</span>
705
- <span class="cline-any cline-yes">5x</span>
706
- <span class="cline-any cline-yes">5x</span>
707
- <span class="cline-any cline-yes">5x</span>
708
- <span class="cline-any cline-yes">5x</span>
709
- <span class="cline-any cline-yes">5x</span>
710
- <span class="cline-any cline-neutral">&nbsp;</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-yes">5x</span>
714
- <span class="cline-any cline-yes">2x</span>
715
- <span class="cline-any cline-yes">2x</span>
716
- <span class="cline-any cline-yes">2x</span>
717
- <span class="cline-any cline-yes">2x</span>
718
- <span class="cline-any cline-yes">2x</span>
719
- <span class="cline-any cline-yes">2x</span>
720
- <span class="cline-any cline-yes">2x</span>
721
- <span class="cline-any cline-yes">2x</span>
722
- <span class="cline-any cline-yes">5x</span>
723
- <span class="cline-any cline-yes">5x</span>
724
- <span class="cline-any cline-yes">5x</span>
725
- <span class="cline-any cline-yes">5x</span>
726
- <span class="cline-any cline-yes">5x</span>
727
- <span class="cline-any cline-neutral">&nbsp;</span>
728
- <span class="cline-any cline-neutral">&nbsp;</span>
729
- <span class="cline-any cline-neutral">&nbsp;</span>
730
- <span class="cline-any cline-yes">12x</span>
731
- <span class="cline-any cline-yes">70x</span>
732
- <span class="cline-any cline-yes">11x</span>
733
- <span class="cline-any cline-yes">11x</span>
734
- <span class="cline-any cline-yes">11x</span>
735
- <span class="cline-any cline-yes">70x</span>
736
- <span class="cline-any cline-neutral">&nbsp;</span>
737
- <span class="cline-any cline-yes">12x</span>
738
- <span class="cline-any cline-yes">52x</span>
739
- <span class="cline-any cline-yes">52x</span>
740
- <span class="cline-any cline-yes">52x</span>
741
- <span class="cline-any cline-yes">52x</span>
742
- <span class="cline-any cline-yes">52x</span>
743
- <span class="cline-any cline-yes">52x</span>
744
- <span class="cline-any cline-yes">52x</span>
745
- <span class="cline-any cline-yes">52x</span>
746
- <span class="cline-any cline-neutral">&nbsp;</span>
747
- <span class="cline-any cline-neutral">&nbsp;</span>
748
- <span class="cline-any cline-neutral">&nbsp;</span>
749
- <span class="cline-any cline-neutral">&nbsp;</span>
750
- <span class="cline-any cline-neutral">&nbsp;</span>
751
- <span class="cline-any cline-neutral">&nbsp;</span>
752
- <span class="cline-any cline-neutral">&nbsp;</span>
753
- <span class="cline-any cline-yes">12x</span>
754
- <span class="cline-any cline-yes">44x</span>
755
- <span class="cline-any cline-yes">44x</span>
756
- <span class="cline-any cline-yes">44x</span>
757
- <span class="cline-any cline-yes">44x</span>
758
- <span class="cline-any cline-no">&nbsp;</span>
759
- <span class="cline-any cline-no">&nbsp;</span>
760
- <span class="cline-any cline-no">&nbsp;</span>
761
- <span class="cline-any cline-yes">44x</span>
762
- <span class="cline-any cline-yes">44x</span>
763
- <span class="cline-any cline-yes">44x</span>
764
- <span class="cline-any cline-yes">44x</span>
765
- <span class="cline-any cline-yes">44x</span>
766
- <span class="cline-any cline-yes">44x</span>
767
- <span class="cline-any cline-yes">44x</span>
768
- <span class="cline-any cline-yes">41x</span>
769
- <span class="cline-any cline-yes">41x</span>
770
- <span class="cline-any cline-yes">44x</span>
771
- <span class="cline-any cline-yes">3x</span>
772
- <span class="cline-any cline-yes">3x</span>
773
- <span class="cline-any cline-neutral">&nbsp;</span>
774
- <span class="cline-any cline-neutral">&nbsp;</span>
775
- <span class="cline-any cline-neutral">&nbsp;</span>
776
- <span class="cline-any cline-yes">2x</span>
777
- <span class="cline-any cline-yes">2x</span>
778
- <span class="cline-any cline-yes">2x</span>
779
- <span class="cline-any cline-yes">2x</span>
780
- <span class="cline-any cline-yes">2x</span>
781
- <span class="cline-any cline-yes">2x</span>
782
- <span class="cline-any cline-yes">2x</span>
783
- <span class="cline-any cline-yes">2x</span>
784
- <span class="cline-any cline-yes">2x</span>
785
- <span class="cline-any cline-yes">2x</span>
786
- <span class="cline-any cline-yes">2x</span>
787
- <span class="cline-any cline-yes">2x</span>
788
- <span class="cline-any cline-yes">2x</span>
789
- <span class="cline-any cline-yes">2x</span>
790
- <span class="cline-any cline-yes">2x</span>
791
- <span class="cline-any cline-yes">2x</span>
792
- <span class="cline-any cline-yes">2x</span>
793
- <span class="cline-any cline-yes">1x</span>
794
- <span class="cline-any cline-yes">1x</span>
795
- <span class="cline-any cline-yes">1x</span>
796
- <span class="cline-any cline-yes">1x</span>
797
- <span class="cline-any cline-yes">1x</span>
798
- <span class="cline-any cline-yes">1x</span>
799
- <span class="cline-any cline-yes">1x</span>
800
- <span class="cline-any cline-yes">1x</span>
801
- <span class="cline-any cline-yes">1x</span>
802
- <span class="cline-any cline-neutral">&nbsp;</span>
803
- <span class="cline-any cline-neutral">&nbsp;</span>
804
- <span class="cline-any cline-yes">1x</span>
805
- <span class="cline-any cline-yes">1x</span>
806
- <span class="cline-any cline-yes">44x</span>
807
- <span class="cline-any cline-yes">44x</span>
808
- <span class="cline-any cline-yes">44x</span>
809
- <span class="cline-any cline-yes">44x</span>
810
- <span class="cline-any cline-neutral">&nbsp;</span>
811
- <span class="cline-any cline-neutral">&nbsp;</span>
812
- <span class="cline-any cline-neutral">&nbsp;</span>
813
- <span class="cline-any cline-neutral">&nbsp;</span>
814
- <span class="cline-any cline-neutral">&nbsp;</span>
815
- <span class="cline-any cline-neutral">&nbsp;</span>
816
- <span class="cline-any cline-neutral">&nbsp;</span>
817
- <span class="cline-any cline-neutral">&nbsp;</span>
818
- <span class="cline-any cline-yes">12x</span>
819
- <span class="cline-any cline-yes">9x</span>
820
- <span class="cline-any cline-yes">1x</span>
821
- <span class="cline-any cline-yes">1x</span>
822
- <span class="cline-any cline-yes">1x</span>
823
- <span class="cline-any cline-yes">1x</span>
824
- <span class="cline-any cline-yes">1x</span>
825
- <span class="cline-any cline-yes">1x</span>
826
- <span class="cline-any cline-yes">1x</span>
827
- <span class="cline-any cline-yes">1x</span>
828
- <span class="cline-any cline-yes">1x</span>
829
- <span class="cline-any cline-yes">1x</span>
830
- <span class="cline-any cline-yes">1x</span>
831
- <span class="cline-any cline-yes">1x</span>
832
- <span class="cline-any cline-yes">1x</span>
833
- <span class="cline-any cline-yes">1x</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">1x</span>
843
- <span class="cline-any cline-yes">1x</span>
844
- <span class="cline-any cline-yes">1x</span>
845
- <span class="cline-any cline-yes">1x</span>
846
- <span class="cline-any cline-neutral">&nbsp;</span>
847
- <span class="cline-any cline-yes">9x</span>
848
- <span class="cline-any cline-yes">1x</span>
849
- <span class="cline-any cline-yes">1x</span>
850
- <span class="cline-any cline-yes">1x</span>
851
- <span class="cline-any cline-yes">1x</span>
852
- <span class="cline-any cline-yes">1x</span>
853
- <span class="cline-any cline-yes">1x</span>
854
- <span class="cline-any cline-yes">1x</span>
855
- <span class="cline-any cline-yes">9x</span>
856
- <span class="cline-any cline-neutral">&nbsp;</span>
857
- <span class="cline-any cline-neutral">&nbsp;</span>
858
- <span class="cline-any cline-neutral">&nbsp;</span>
859
- <span class="cline-any cline-neutral">&nbsp;</span>
860
- <span class="cline-any cline-neutral">&nbsp;</span>
861
- <span class="cline-any cline-neutral">&nbsp;</span>
862
- <span class="cline-any cline-yes">12x</span>
863
- <span class="cline-any cline-yes">2x</span>
864
- <span class="cline-any cline-neutral">&nbsp;</span>
865
- <span class="cline-any cline-neutral">&nbsp;</span>
866
- <span class="cline-any cline-neutral">&nbsp;</span>
867
- <span class="cline-any cline-neutral">&nbsp;</span>
868
- <span class="cline-any cline-neutral">&nbsp;</span>
869
- <span class="cline-any cline-neutral">&nbsp;</span>
870
- <span class="cline-any cline-neutral">&nbsp;</span>
871
- <span class="cline-any cline-yes">2x</span>
872
- <span class="cline-any cline-yes">2x</span>
873
- <span class="cline-any cline-yes">2x</span>
874
- <span class="cline-any cline-yes">1x</span>
875
- <span class="cline-any cline-yes">2x</span>
876
- <span class="cline-any cline-no">&nbsp;</span>
877
- <span class="cline-any cline-no">&nbsp;</span>
878
- <span class="cline-any cline-yes">2x</span>
879
- <span class="cline-any cline-yes">2x</span>
880
- <span class="cline-any cline-yes">2x</span>
881
- <span class="cline-any cline-yes">2x</span>
882
- <span class="cline-any cline-yes">2x</span>
883
- <span class="cline-any cline-yes">2x</span>
884
- <span class="cline-any cline-yes">2x</span>
885
- <span class="cline-any cline-yes">1x</span>
886
- <span class="cline-any cline-yes">1x</span>
887
- <span class="cline-any cline-yes">1x</span>
888
- <span class="cline-any cline-yes">1x</span>
889
- <span class="cline-any cline-neutral">&nbsp;</span>
890
- <span class="cline-any cline-yes">1x</span>
891
- <span class="cline-any cline-yes">1x</span>
892
- <span class="cline-any cline-yes">1x</span>
893
- <span class="cline-any cline-yes">1x</span>
894
- <span class="cline-any cline-yes">2x</span>
895
- <span class="cline-any cline-yes">12x</span>
896
- <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import type { ConnectionState, ReconnectConfig } from '../../types';
897
- import { withTimeout } from '../../utils/index';
898
- import type { Logger } from '../logger/index';
899
- import type { RemoteDatabaseService } from './remote';
900
- &nbsp;
901
- /**
902
- * Keeps the remote WebSocket alive for the whole life of the page.
903
- *
904
- * The SurrealDB SDK reconnects on its own after a socket `close`, but that
905
- * covers only one of three ways the connection dies:
906
- *
907
- * 1. **Socket closes, SDK recovers.** Handled entirely by the SDK. This
908
- * supervisor only observes it (to report `reconnecting` upward).
909
- * 2. **Socket closes, SDK gives up.** With `attempts: -1` this shouldn't happen
910
- * from exhaustion — but the SDK also terminates the engine permanently when
911
- * its post-reconnect handshake throws (it re-runs `version()`, `use()`,
912
- * `authenticate()` on every reconnect and closes the engine on any error).
913
- * One transient hiccup there would otherwise kill the page's connection for
914
- * good. The revive loop re-opens from scratch.
915
- * 3. **Socket never closes at all.** A half-open connection: the peer is gone
916
- * (NAT timeout, wifi switch, laptop sleep) but no FIN ever arrives, so
917
- * `readyState` stays OPEN and the SDK's own 30s ping — fire-and-forget, no
918
- * response deadline — never notices. Nothing ever fires a `close` event, so
919
- * nothing ever triggers a reconnect. The heartbeat detects this and forces
920
- * the teardown that case 2's loop then repairs.
921
- *
922
- * Plus wake triggers: coming back `online` or un-hiding the tab probes
923
- * immediately rather than waiting out a backoff that was scheduled while the
924
- * network was known-down.
925
- */
926
- export class ConnectionSupervisor {
927
- private readonly logger: Logger;
928
- private readonly config: Required&lt;ReconnectConfig&gt;;
929
- &nbsp;
930
- private state: ConnectionState = 'disconnected';
931
- private subscribers = new Set&lt;(state: ConnectionState) =&gt; void&gt;();
932
- &nbsp;
933
- private started = false;
934
- private disposed = false;
935
- &nbsp;
936
- private heartbeatTimer: ReturnType&lt;typeof setTimeout&gt; | null = null;
937
- private heartbeatInFlight = false;
938
- /** Consecutive failed probes. See {@link FAILURES_BEFORE_TEARDOWN}. */
939
- private heartbeatFailures = 0;
940
- &nbsp;
941
- private reviveTimer: ReturnType&lt;typeof setTimeout&gt; | null = null;
942
- private reviveAttempts = 0;
943
- /** Timestamp of the last wake-triggered probe, for rate limiting. */
944
- private lastWakeProbeAt = 0;
945
- private reviving = false;
946
- /**
947
- * Set while the browser reports itself offline. Retrying a socket against a
948
- * down interface only burns backoff, so the loop parks until `online` fires.
949
- */
950
- private suspended = false;
951
- &nbsp;
952
- private teardown: Array&lt;() =&gt; void&gt; = [];
953
- &nbsp;
954
- private static readonly REVIVE_BASE_MS = 1_000;
955
- /**
956
- * How many consecutive heartbeat failures it takes to tear the socket down.
957
- *
958
- * The probe rides the same serialized queue as every other RPC (deliberately
959
- * — see {@link beat}), which means it cannot distinguish a WEDGED queue from
960
- * a merely BUSY one. A single slow window (a large sync burst, one heavy
961
- * app query) used to be enough to force-close a perfectly healthy socket,
962
- * and the resulting reconnect re-registered every active query about a
963
- * second later. That self-inflicted teardown manufactured the very reconnect
964
- * storms this class exists to survive. A genuinely dead socket still fails
965
- * every probe, so it is torn down one interval later than before.
966
- */
967
- private static readonly FAILURES_BEFORE_TEARDOWN = 2;
968
- /** Retry delay after an inconclusive (first) heartbeat failure. */
969
- private static readonly HEARTBEAT_RETRY_MS = 5_000;
970
- /** Floor between probes triggered by wake events (tab focus, pageshow). */
971
- private static readonly WAKE_PROBE_MIN_INTERVAL_MS = 10_000;
972
- &nbsp;
973
- constructor(
974
- private readonly remote: RemoteDatabaseService,
975
- logger: Logger,
976
- config?: Required&lt;ReconnectConfig&gt;
977
- ) {
978
- this.logger = logger.child({ service: 'ConnectionSupervisor' });
979
- this.config = <span class="branch-0 cbranch-no" title="branch not covered" >config ?? remote.getReconnectConfig();</span>
980
- }
981
- &nbsp;
982
- /** Latest observed transport state. */
983
- get connection(): ConnectionState {
984
- return this.state;
985
- }
986
- &nbsp;
987
- /**
988
- * Observe transport state. Fires immediately with the current value and again
989
- * on every change. Returns an unsubscribe.
990
- */
991
- subscribe(cb: (state: ConnectionState) =&gt; void): () =&gt; void {
992
- cb(this.state);
993
- this.subscribers.add(cb);
994
- return () =&gt; {
995
- <span class="cstat-no" title="statement not covered" > this.subscribers.delete(cb);</span>
996
- <span class="cstat-no" title="statement not covered" > };</span>
997
- }
998
- &nbsp;
999
- /**
1000
- * Begin supervising. Call once, after the initial {@link
1001
- * RemoteDatabaseService.connect}. Idempotent.
1002
- */
1003
- start(): void {
1004
- if (this.started || this.disposed) <span class="branch-0 cbranch-no" title="branch not covered" >return;</span>
1005
- this.started = true;
1006
- &nbsp;
1007
- this.setState(this.remote.getStatus());
1008
- &nbsp;
1009
- this.teardown.push(
1010
- this.remote.subscribeConnection('connecting', () =&gt; this.setState('connecting')),
1011
- this.remote.subscribeConnection('reconnecting', () =&gt; {
1012
- this.setState('reconnecting');
1013
- // The SDK owns the retry from here; ours would fight it for the socket.
1014
- this.stopHeartbeat();
1015
- }),
1016
- this.remote.subscribeConnection('connected', () =&gt; {
1017
- this.reviveAttempts = 0;
1018
- this.clearReviveTimer();
1019
- this.setState('connected');
1020
- this.startHeartbeat();
1021
- }),
1022
- this.remote.subscribeConnection('disconnected', () =&gt; {
1023
- this.setState('disconnected');
1024
- this.stopHeartbeat();
1025
- // The SDK has stopped trying (exhausted, terminated, or handshake
1026
- // failure). From here on, reconnecting is entirely our job.
1027
- this.scheduleRevive();
1028
- }),
1029
- this.remote.subscribeConnection('error', (err) =&gt; {
1030
- <span class="cstat-no" title="statement not covered" > this.logger.debug(</span>
1031
- <span class="cstat-no" title="statement not covered" > { err, Category: 'sp00ky-client::ConnectionSupervisor::error' },</span>
1032
- <span class="cstat-no" title="statement not covered" > 'Transport error'</span>
1033
- <span class="cstat-no" title="statement not covered" > );</span>
1034
- })
1035
- );
1036
- &nbsp;
1037
- this.installWakeTriggers();
1038
- &nbsp;
1039
- if (this.state === 'connected') this.startHeartbeat(<span class="branch-0 cbranch-no" title="branch not covered" >);</span>
1040
- <span class="cstat-no" title="statement not covered" > else this.scheduleRevive();</span>
1041
- }
1042
- &nbsp;
1043
- /** Stop all timers and listeners. Safe to call more than once. */
1044
- dispose(): void {
1045
- this.disposed = true;
1046
- this.started = false;
1047
- this.stopHeartbeat();
1048
- this.clearReviveTimer();
1049
- for (const off of this.teardown) {
1050
- try {
1051
- off();
1052
- <span class="branch-0 cbranch-no" title="branch not covered" > } catch {</span>
1053
- /* ignore */
1054
- <span class="cstat-no" title="statement not covered" > }</span>
1055
- }
1056
- this.teardown = [];
1057
- this.subscribers.clear();
1058
- }
1059
- &nbsp;
1060
- private setState(next: ConnectionState): void {
1061
- if (this.state === next) return;
1062
- this.state = next;
1063
- this.logger.info(
1064
- { state: next, Category: 'sp00ky-client::ConnectionSupervisor::state' },
1065
- 'Connection state changed'
1066
- );
1067
- for (const cb of this.subscribers) {
1068
- try {
1069
- cb(next);
1070
- <span class="branch-0 cbranch-no" title="branch not covered" > } catch (err) {</span>
1071
- <span class="cstat-no" title="statement not covered" > this.logger.debug(</span>
1072
- <span class="cstat-no" title="statement not covered" > { err, Category: 'sp00ky-client::ConnectionSupervisor::state' },</span>
1073
- <span class="cstat-no" title="statement not covered" > 'Connection subscriber threw'</span>
1074
- <span class="cstat-no" title="statement not covered" > );</span>
1075
- <span class="cstat-no" title="statement not covered" > }</span>
1076
- }
1077
- }
1078
- &nbsp;
1079
- // ---- Revive loop -------------------------------------------------------
1080
- &nbsp;
1081
- private clearReviveTimer(): void {
1082
- if (this.reviveTimer !== null) {
1083
- clearTimeout(this.reviveTimer);
1084
- this.reviveTimer = null;
1085
- }
1086
- }
1087
- &nbsp;
1088
- /**
1089
- * Queue the next `connect()` attempt on exponential backoff, capped at
1090
- * `superviseRetryDelayMaxMs`. Never gives up — the page is expected to
1091
- * outlive any outage.
1092
- */
1093
- private scheduleRevive(): void {
1094
- if (this.disposed || this.suspended) <span class="branch-0 cbranch-no" title="branch not covered" >return;</span>
1095
- if (this.reviveTimer !== null || this.reviving) return;
1096
- const delay = Math.min(
1097
- this.config.superviseRetryDelayMaxMs,
1098
- ConnectionSupervisor.REVIVE_BASE_MS * 2 ** this.reviveAttempts
1099
- );
1100
- this.reviveTimer = setTimeout(() =&gt; {
1101
- this.reviveTimer = null;
1102
- void this.revive();
1103
- }, delay);
1104
- }
1105
- &nbsp;
1106
- private async revive(): Promise&lt;void&gt; {
1107
- if (this.disposed || this.suspended || this.reviving) <span class="branch-0 cbranch-no" title="branch not covered" >return;</span>
1108
- // The SDK may have recovered on its own between scheduling and firing.
1109
- if (this.remote.getStatus() === 'connected') <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
1110
- <span class="cstat-no" title="statement not covered" > this.reviveAttempts = 0;</span>
1111
- <span class="cstat-no" title="statement not covered" > return;</span>
1112
- <span class="cstat-no" title="statement not covered" > }</span>
1113
- this.reviving = true;
1114
- this.reviveAttempts++;
1115
- this.setState('reconnecting');
1116
- this.logger.info(
1117
- {
1118
- attempt: this.reviveAttempts,
1119
- Category: 'sp00ky-client::ConnectionSupervisor::revive',
1120
- },
1121
- 'Re-opening the remote connection'
1122
- );
1123
- try {
1124
- await this.remote.connect();
1125
- // Don't reset `reviveAttempts` or start the heartbeat here — the
1126
- // `connected` handler does both, and it's the only signal that the
1127
- // handshake (version/use/authenticate) actually completed.
1128
- } catch (err) {
1129
- this.logger.warn(
1130
- {
1131
- err,
1132
- attempt: this.reviveAttempts,
1133
- Category: 'sp00ky-client::ConnectionSupervisor::revive',
1134
- },
1135
- 'Reconnect attempt failed; will retry'
1136
- );
1137
- } finally {
1138
- this.reviving = false;
1139
- }
1140
- if (this.remote.getStatus() !== 'connected') this.scheduleRevive();
1141
- }
1142
- &nbsp;
1143
- // ---- Heartbeat watchdog ------------------------------------------------
1144
- &nbsp;
1145
- private stopHeartbeat(): void {
1146
- if (this.heartbeatTimer !== null) {
1147
- clearTimeout(this.heartbeatTimer);
1148
- this.heartbeatTimer = null;
1149
- }
1150
- }
1151
- &nbsp;
1152
- private startHeartbeat(): void {
1153
- this.stopHeartbeat();
1154
- if (this.disposed || this.suspended) <span class="branch-0 cbranch-no" title="branch not covered" >return;</span>
1155
- if (!(this.config.heartbeatIntervalMs &gt; 0)) <span class="branch-0 cbranch-no" title="branch not covered" >return;</span>
1156
- this.heartbeatTimer = setTimeout(
1157
- () =&gt; void this.beat(),
1158
- this.config.heartbeatIntervalMs
1159
- );
1160
- }
1161
- &nbsp;
1162
- /**
1163
- * Probe the server end-to-end. Deliberately goes through
1164
- * `remote.query` — the same serialized queue every other remote call uses —
1165
- * so a queue wedged behind a stuck RPC also fails the heartbeat instead of
1166
- * being invisible to it.
1167
- */
1168
- private async beat(): Promise&lt;void&gt; {
1169
- this.heartbeatTimer = null;
1170
- if (this.disposed || this.suspended) <span class="branch-0 cbranch-no" title="branch not covered" >return;</span>
1171
- if (this.remote.getStatus() !== 'connected') <span class="branch-0 cbranch-no" title="branch not covered" >return;</span>
1172
- if (this.heartbeatInFlight) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
1173
- <span class="cstat-no" title="statement not covered" > this.startHeartbeat();</span>
1174
- <span class="cstat-no" title="statement not covered" > return;</span>
1175
- <span class="cstat-no" title="statement not covered" > }</span>
1176
- this.heartbeatInFlight = true;
1177
- try {
1178
- await withTimeout(
1179
- this.remote.query('RETURN true'),
1180
- this.config.heartbeatTimeoutMs,
1181
- `Heartbeat timed out after ${this.config.heartbeatTimeoutMs}ms`
1182
- );
1183
- this.heartbeatFailures = 0;
1184
- this.startHeartbeat();
1185
- } catch (err) {
1186
- this.heartbeatFailures++;
1187
- if (this.heartbeatFailures &lt; ConnectionSupervisor.FAILURES_BEFORE_TEARDOWN) {
1188
- // Inconclusive: the probe shares a queue with ordinary traffic, so this
1189
- // may just be a busy window rather than a dead socket. Re-probe soon
1190
- // instead of tearing down a connection that is probably fine.
1191
- this.logger.debug(
1192
- {
1193
- err,
1194
- failures: this.heartbeatFailures,
1195
- Category: 'sp00ky-client::ConnectionSupervisor::heartbeat',
1196
- },
1197
- 'Heartbeat failed; re-probing before tearing the socket down'
1198
- );
1199
- this.stopHeartbeat();
1200
- if (!this.disposed &amp;&amp; !this.suspended) {
1201
- this.heartbeatTimer = setTimeout(
1202
- () =&gt; void this.beat(),
1203
- Math.min(ConnectionSupervisor.HEARTBEAT_RETRY_MS, this.config.heartbeatIntervalMs)
1204
- );
1205
- }
1206
- return;
1207
- }
1208
- this.logger.warn(
1209
- {
1210
- err,
1211
- failures: this.heartbeatFailures,
1212
- Category: 'sp00ky-client::ConnectionSupervisor::heartbeat',
1213
- },
1214
- 'Heartbeat failed repeatedly; tearing the socket down to force a reconnect'
1215
- );
1216
- this.heartbeatFailures = 0;
1217
- // Force the `close` the transport never delivered. The resulting
1218
- // `disconnected` event drives the revive loop.
1219
- await this.remote.forceClose();
1220
- if (this.remote.getStatus() !== 'connected') this.scheduleRevive();
1221
- } finally {
1222
- this.heartbeatInFlight = false;
1223
- }
1224
- }
1225
- &nbsp;
1226
- // ---- Wake triggers -----------------------------------------------------
1227
- &nbsp;
1228
- /**
1229
- * A restored network or an un-hidden tab is the strongest available hint that
1230
- * a reconnect will now succeed, so probe immediately instead of waiting out a
1231
- * backoff scheduled under worse conditions.
1232
- */
1233
- private installWakeTriggers(): void {
1234
- if (typeof window !== 'undefined' &amp;&amp; typeof window.addEventListener === 'function') {
1235
- const onOnline = () =&gt; {
1236
- this.suspended = false;
1237
- this.wake('online');
1238
- };
1239
- const onOffline = () =&gt; {
1240
- this.logger.info(
1241
- { Category: 'sp00ky-client::ConnectionSupervisor::offline' },
1242
- 'Browser reports offline; parking reconnects until online'
1243
- );
1244
- this.suspended = true;
1245
- this.stopHeartbeat();
1246
- this.clearReviveTimer();
1247
- this.setState('disconnected');
1248
- };
1249
- window.addEventListener('online', onOnline);
1250
- window.addEventListener('offline', onOffline);
1251
- this.teardown.push(
1252
- () =&gt; window.removeEventListener('online', onOnline),
1253
- () =&gt; window.removeEventListener('offline', onOffline)
1254
- );
1255
- // A tab restored from bfcache keeps its dead socket; `pageshow` is the
1256
- // only event that fires in that path.
1257
- const onPageShow = <span class="fstat-no" title="function not covered" >() =&gt; this.wake('pageshow');</span>
1258
- window.addEventListener('pageshow', onPageShow);
1259
- this.teardown.push(() =&gt; window.removeEventListener('pageshow', onPageShow));
1260
- }
1261
- &nbsp;
1262
- if (typeof document !== 'undefined' &amp;&amp; typeof document.addEventListener === 'function') {
1263
- const onVisibility = () =&gt; {
1264
- if (document.visibilityState !== 'visible') <span class="branch-0 cbranch-no" title="branch not covered" >return;</span>
1265
- this.wake('visibilitychange');
1266
- };
1267
- document.addEventListener('visibilitychange', onVisibility);
1268
- this.teardown.push(() =&gt; document.removeEventListener('visibilitychange', onVisibility));
1269
- }
1270
- }
1271
- &nbsp;
1272
- /**
1273
- * Reset the backoff and act on whichever problem is present: reconnect if the
1274
- * socket is gone, otherwise probe it (it may be half-open — which is exactly
1275
- * what a sleep/wake cycle produces).
1276
- */
1277
- private wake(reason: string): void {
1278
- if (this.disposed || this.suspended) <span class="branch-0 cbranch-no" title="branch not covered" >return;</span>
1279
- // `visibilitychange` fires on every alt-tab, every window minimise and every
1280
- // focus change. Probing a connected socket each time meant an ordinary
1281
- // afternoon of tab-switching issued a steady stream of extra RPCs, each of
1282
- // which could trip the heartbeat teardown above. A healthy socket does not
1283
- // become unhealthy because the user looked away for four seconds, so probes
1284
- // from wake triggers are rate-limited; a genuinely dead socket is still
1285
- // caught by the regular heartbeat.
1286
- const now = Date.now();
1287
- if (
1288
- this.remote.getStatus() === 'connected' &amp;&amp;
1289
- now - this.lastWakeProbeAt &lt; ConnectionSupervisor.WAKE_PROBE_MIN_INTERVAL_MS
1290
- ) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
1291
- <span class="cstat-no" title="statement not covered" > return;</span>
1292
- <span class="cstat-no" title="statement not covered" > }</span>
1293
- this.lastWakeProbeAt = now;
1294
- this.logger.debug(
1295
- { reason, state: this.state, Category: 'sp00ky-client::ConnectionSupervisor::wake' },
1296
- 'Wake trigger; probing the connection'
1297
- );
1298
- this.reviveAttempts = 0;
1299
- if (this.remote.getStatus() === 'connected') {
1300
- this.stopHeartbeat();
1301
- void this.beat();
1302
- return;
1303
- }
1304
- // 'reconnecting' means the SDK's own loop owns the socket; don't race it.
1305
- if (this.remote.getStatus() === 'disconnected') {
1306
- this.clearReviveTimer();
1307
- void this.revive();
1308
- }
1309
- }
1310
- }
1311
- &nbsp;</pre></td></tr></table></pre>
1312
-
1313
- <div class='push'></div><!-- for sticky footer -->
1314
- </div><!-- /wrapper -->
1315
- <div class='footer quiet pad2 space-top1 center small'>
1316
- Code coverage generated by
1317
- <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
1318
- at 2026-09-09T09:49:51.780Z
1319
- </div>
1320
- <script src="../../../prettify.js"></script>
1321
- <script>
1322
- window.onload = function () {
1323
- prettyPrint();
1324
- };
1325
- </script>
1326
- <script src="../../../sorter.js"></script>
1327
- <script src="../../../block-navigation.js"></script>
1328
- </body>
1329
- </html>
1330
-