@studious-lms/server 1.2.45 → 1.2.46

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 (231) hide show
  1. package/.env.example +45 -0
  2. package/.env.test.example +37 -0
  3. package/README.md +34 -7
  4. package/coverage/base.css +224 -0
  5. package/coverage/block-navigation.js +87 -0
  6. package/coverage/clover.xml +12110 -0
  7. package/coverage/coverage-final.json +44 -0
  8. package/coverage/favicon.png +0 -0
  9. package/coverage/index.html +221 -0
  10. package/coverage/prettify.css +1 -0
  11. package/coverage/prettify.js +2 -0
  12. package/coverage/server/index.html +116 -0
  13. package/coverage/server/src/exportType.ts.html +109 -0
  14. package/coverage/server/src/index.html +161 -0
  15. package/coverage/server/src/index.ts.html +1702 -0
  16. package/coverage/server/src/instrument.ts.html +130 -0
  17. package/coverage/server/src/lib/config/env.ts.html +448 -0
  18. package/coverage/server/src/lib/config/index.html +116 -0
  19. package/coverage/server/src/lib/fileUpload.ts.html +1138 -0
  20. package/coverage/server/src/lib/googleCloudStorage.ts.html +334 -0
  21. package/coverage/server/src/lib/index.html +206 -0
  22. package/coverage/server/src/lib/jsonConversion.ts.html +2323 -0
  23. package/coverage/server/src/lib/jsonStyles.ts.html +193 -0
  24. package/coverage/server/src/lib/notificationHandler.ts.html +193 -0
  25. package/coverage/server/src/lib/pusher.ts.html +121 -0
  26. package/coverage/server/src/lib/thumbnailGenerator.ts.html +592 -0
  27. package/coverage/server/src/middleware/auth.ts.html +646 -0
  28. package/coverage/server/src/middleware/index.html +146 -0
  29. package/coverage/server/src/middleware/logging.ts.html +244 -0
  30. package/coverage/server/src/middleware/security.ts.html +271 -0
  31. package/coverage/server/src/routers/_app.ts.html +232 -0
  32. package/coverage/server/src/routers/agenda.ts.html +319 -0
  33. package/coverage/server/src/routers/announcement.ts.html +3481 -0
  34. package/coverage/server/src/routers/assignment.ts.html +7633 -0
  35. package/coverage/server/src/routers/attendance.ts.html +1030 -0
  36. package/coverage/server/src/routers/auth.ts.html +1081 -0
  37. package/coverage/server/src/routers/class.ts.html +3535 -0
  38. package/coverage/server/src/routers/comment.ts.html +991 -0
  39. package/coverage/server/src/routers/conversation.ts.html +982 -0
  40. package/coverage/server/src/routers/event.ts.html +1609 -0
  41. package/coverage/server/src/routers/file.ts.html +1144 -0
  42. package/coverage/server/src/routers/folder.ts.html +2797 -0
  43. package/coverage/server/src/routers/index.html +386 -0
  44. package/coverage/server/src/routers/labChat.ts.html +3073 -0
  45. package/coverage/server/src/routers/marketing.ts.html +340 -0
  46. package/coverage/server/src/routers/message.ts.html +1912 -0
  47. package/coverage/server/src/routers/notifications.ts.html +364 -0
  48. package/coverage/server/src/routers/section.ts.html +1120 -0
  49. package/coverage/server/src/routers/user.ts.html +862 -0
  50. package/coverage/server/src/routers/worksheet.ts.html +1729 -0
  51. package/coverage/server/src/trpc.ts.html +397 -0
  52. package/coverage/server/src/types/index.html +116 -0
  53. package/coverage/server/src/types/trpc.ts.html +127 -0
  54. package/coverage/server/src/utils/aiUser.ts.html +280 -0
  55. package/coverage/server/src/utils/email.ts.html +121 -0
  56. package/coverage/server/src/utils/generateInviteCode.ts.html +106 -0
  57. package/coverage/server/src/utils/index.html +206 -0
  58. package/coverage/server/src/utils/inference.ts.html +709 -0
  59. package/coverage/server/src/utils/logger.ts.html +664 -0
  60. package/coverage/server/src/utils/prismaErrorHandler.ts.html +907 -0
  61. package/coverage/server/src/utils/prismaWrapper.ts.html +355 -0
  62. package/coverage/server/vitest.config.ts.html +196 -0
  63. package/coverage/sort-arrow-sprite.png +0 -0
  64. package/coverage/sorter.js +210 -0
  65. package/dist/index.d.ts.map +1 -1
  66. package/dist/index.js +83 -52
  67. package/dist/index.js.map +1 -1
  68. package/dist/instrument.js +15 -8
  69. package/dist/instrument.js.map +1 -1
  70. package/dist/lib/config/env.d.ts +169 -0
  71. package/dist/lib/config/env.d.ts.map +1 -0
  72. package/dist/lib/config/env.js +115 -0
  73. package/dist/lib/config/env.js.map +1 -0
  74. package/dist/lib/fileUpload.d.ts.map +1 -1
  75. package/dist/lib/fileUpload.js +5 -4
  76. package/dist/lib/fileUpload.js.map +1 -1
  77. package/dist/lib/googleCloudStorage.d.ts.map +1 -1
  78. package/dist/lib/googleCloudStorage.js +7 -8
  79. package/dist/lib/googleCloudStorage.js.map +1 -1
  80. package/dist/lib/jsonConversion.d.ts.map +1 -1
  81. package/dist/lib/jsonConversion.js +14 -16
  82. package/dist/lib/jsonConversion.js.map +1 -1
  83. package/dist/lib/notificationHandler.d.ts +2 -2
  84. package/dist/lib/prisma.d.ts +2 -2
  85. package/dist/lib/prisma.d.ts.map +1 -1
  86. package/dist/lib/prisma.js +22 -3
  87. package/dist/lib/prisma.js.map +1 -1
  88. package/dist/lib/pusher.d.ts.map +1 -1
  89. package/dist/lib/pusher.js +8 -7
  90. package/dist/lib/pusher.js.map +1 -1
  91. package/dist/middleware/auth.d.ts.map +1 -1
  92. package/dist/middleware/auth.js +6 -5
  93. package/dist/middleware/auth.js.map +1 -1
  94. package/dist/middleware/security.d.ts +5 -0
  95. package/dist/middleware/security.d.ts.map +1 -0
  96. package/dist/middleware/security.js +77 -0
  97. package/dist/middleware/security.js.map +1 -0
  98. package/dist/routers/_app.d.ts +294 -98
  99. package/dist/routers/_app.d.ts.map +1 -1
  100. package/dist/routers/_app.js +4 -2
  101. package/dist/routers/_app.js.map +1 -1
  102. package/dist/routers/agenda.d.ts.map +1 -1
  103. package/dist/routers/agenda.js +12 -9
  104. package/dist/routers/agenda.js.map +1 -1
  105. package/dist/routers/announcement.d.ts +8 -0
  106. package/dist/routers/announcement.d.ts.map +1 -1
  107. package/dist/routers/announcement.js +6 -4
  108. package/dist/routers/announcement.js.map +1 -1
  109. package/dist/routers/assignment.d.ts +7 -4
  110. package/dist/routers/assignment.d.ts.map +1 -1
  111. package/dist/routers/assignment.js +35 -18
  112. package/dist/routers/assignment.js.map +1 -1
  113. package/dist/routers/attendance.d.ts +1 -0
  114. package/dist/routers/attendance.d.ts.map +1 -1
  115. package/dist/routers/attendance.js +4 -4
  116. package/dist/routers/attendance.js.map +1 -1
  117. package/dist/routers/auth.d.ts +20 -0
  118. package/dist/routers/auth.d.ts.map +1 -1
  119. package/dist/routers/auth.js +132 -15
  120. package/dist/routers/auth.js.map +1 -1
  121. package/dist/routers/class.d.ts +10 -0
  122. package/dist/routers/class.d.ts.map +1 -1
  123. package/dist/routers/class.js +49 -5
  124. package/dist/routers/class.js.map +1 -1
  125. package/dist/routers/comment.d.ts +2 -0
  126. package/dist/routers/comment.d.ts.map +1 -1
  127. package/dist/routers/conversation.d.ts +1 -0
  128. package/dist/routers/conversation.d.ts.map +1 -1
  129. package/dist/routers/conversation.js +46 -31
  130. package/dist/routers/conversation.js.map +1 -1
  131. package/dist/routers/file.d.ts.map +1 -1
  132. package/dist/routers/file.js +30 -7
  133. package/dist/routers/file.js.map +1 -1
  134. package/dist/routers/labChat.d.ts +1 -0
  135. package/dist/routers/labChat.d.ts.map +1 -1
  136. package/dist/routers/labChat.js +2 -3
  137. package/dist/routers/labChat.js.map +1 -1
  138. package/dist/routers/marketing.d.ts +1 -1
  139. package/dist/routers/newtonChat.d.ts +55 -0
  140. package/dist/routers/newtonChat.d.ts.map +1 -0
  141. package/dist/routers/newtonChat.js +438 -0
  142. package/dist/routers/newtonChat.js.map +1 -0
  143. package/dist/routers/notifications.d.ts +4 -4
  144. package/dist/routers/section.d.ts +9 -4
  145. package/dist/routers/section.d.ts.map +1 -1
  146. package/dist/routers/section.js +8 -8
  147. package/dist/routers/section.js.map +1 -1
  148. package/dist/routers/user.d.ts.map +1 -1
  149. package/dist/routers/user.js +5 -4
  150. package/dist/routers/user.js.map +1 -1
  151. package/dist/routers/worksheet.d.ts +30 -36
  152. package/dist/routers/worksheet.d.ts.map +1 -1
  153. package/dist/routers/worksheet.js +11 -33
  154. package/dist/routers/worksheet.js.map +1 -1
  155. package/dist/seedDatabase.d.ts +1 -1
  156. package/dist/seedDatabase.js +275 -284
  157. package/dist/seedDatabase.js.map +1 -1
  158. package/dist/server/pipelines/aiLabChat.d.ts +10 -0
  159. package/dist/server/pipelines/aiLabChat.d.ts.map +1 -0
  160. package/dist/server/pipelines/aiLabChat.js +83 -0
  161. package/dist/server/pipelines/aiLabChat.js.map +1 -0
  162. package/dist/server/pipelines/gradeWorksheet.d.ts +2 -0
  163. package/dist/server/pipelines/gradeWorksheet.d.ts.map +1 -0
  164. package/dist/server/pipelines/gradeWorksheet.js +138 -0
  165. package/dist/server/pipelines/gradeWorksheet.js.map +1 -0
  166. package/dist/trpc.d.ts.map +1 -1
  167. package/dist/trpc.js +2 -2
  168. package/dist/trpc.js.map +1 -1
  169. package/dist/utils/email.d.ts +9 -1
  170. package/dist/utils/email.d.ts.map +1 -1
  171. package/dist/utils/email.js +20 -5
  172. package/dist/utils/email.js.map +1 -1
  173. package/dist/utils/inference.d.ts +3 -0
  174. package/dist/utils/inference.d.ts.map +1 -1
  175. package/dist/utils/inference.js +41 -7
  176. package/dist/utils/inference.js.map +1 -1
  177. package/dist/utils/logger.d.ts.map +1 -1
  178. package/dist/utils/logger.js +3 -3
  179. package/dist/utils/logger.js.map +1 -1
  180. package/docker-compose.yml +14 -0
  181. package/package.json +13 -4
  182. package/prisma/schema.prisma +32 -5
  183. package/scripts/test-pre-push.ts +14 -0
  184. package/src/index.ts +98 -54
  185. package/src/instrument.ts +13 -6
  186. package/src/lib/config/env.ts +126 -0
  187. package/src/lib/fileUpload.ts +3 -2
  188. package/src/lib/googleCloudStorage.ts +6 -6
  189. package/src/lib/jsonConversion.ts +12 -14
  190. package/src/lib/prisma.ts +23 -2
  191. package/src/lib/pusher.ts +6 -5
  192. package/src/middleware/auth.ts +4 -3
  193. package/src/middleware/security.ts +80 -0
  194. package/src/routers/_app.ts +2 -0
  195. package/src/routers/agenda.ts +10 -7
  196. package/src/routers/announcement.ts +4 -2
  197. package/src/routers/assignment.ts +58 -40
  198. package/src/routers/attendance.ts +2 -2
  199. package/src/routers/auth.ts +143 -14
  200. package/src/routers/class.ts +52 -3
  201. package/src/routers/conversation.ts +49 -29
  202. package/src/routers/file.ts +29 -5
  203. package/src/routers/labChat.ts +0 -1
  204. package/src/routers/newtonChat.ts +520 -0
  205. package/src/routers/section.ts +6 -6
  206. package/src/routers/user.ts +3 -2
  207. package/src/routers/worksheet.ts +9 -37
  208. package/src/seedDatabase.ts +290 -283
  209. package/src/server/pipelines/aiLabChat.ts +92 -0
  210. package/src/server/pipelines/gradeWorksheet.ts +152 -0
  211. package/src/trpc.ts +2 -0
  212. package/src/utils/email.ts +30 -3
  213. package/src/utils/inference.ts +50 -5
  214. package/src/utils/logger.ts +2 -1
  215. package/tests/announcement.test.ts +164 -0
  216. package/tests/assignment.test.ts +296 -0
  217. package/tests/attendance.test.ts +168 -0
  218. package/tests/auth.test.ts +33 -10
  219. package/tests/class.test.ts +34 -9
  220. package/tests/event.test.ts +228 -0
  221. package/tests/section.test.ts +216 -0
  222. package/tests/setup.ts +70 -16
  223. package/tests/user.test.ts +158 -0
  224. package/vitest.config.ts +26 -0
  225. package/API_SPECIFICATION.md +0 -1597
  226. package/BASE64_REMOVAL_SUMMARY.md +0 -164
  227. package/CHAT_API_SPEC.md +0 -579
  228. package/LAB_CHAT_API_SPEC.md +0 -518
  229. package/dist/routers/school.d.ts +0 -208
  230. package/dist/routers/school.d.ts.map +0 -1
  231. package/dist/routers/school.js +0 -483
@@ -0,0 +1,3073 @@
1
+
2
+ <!doctype html>
3
+ <html lang="en">
4
+
5
+ <head>
6
+ <title>Code coverage report for server/src/routers/labChat.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">server/src/routers</a> labChat.ts</h1>
23
+ <div class='clearfix'>
24
+
25
+ <div class='fl pad1y space-right2'>
26
+ <span class="strong">5.56% </span>
27
+ <span class="quiet">Statements</span>
28
+ <span class='fraction'>45/809</span>
29
+ </div>
30
+
31
+
32
+ <div class='fl pad1y space-right2'>
33
+ <span class="strong">100% </span>
34
+ <span class="quiet">Branches</span>
35
+ <span class='fraction'>0/0</span>
36
+ </div>
37
+
38
+
39
+ <div class='fl pad1y space-right2'>
40
+ <span class="strong">0% </span>
41
+ <span class="quiet">Functions</span>
42
+ <span class='fraction'>0/2</span>
43
+ </div>
44
+
45
+
46
+ <div class='fl pad1y space-right2'>
47
+ <span class="strong">5.56% </span>
48
+ <span class="quiet">Lines</span>
49
+ <span class='fraction'>45/809</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 low'></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>
483
+ <a name='L418'></a><a href='#L418'>418</a>
484
+ <a name='L419'></a><a href='#L419'>419</a>
485
+ <a name='L420'></a><a href='#L420'>420</a>
486
+ <a name='L421'></a><a href='#L421'>421</a>
487
+ <a name='L422'></a><a href='#L422'>422</a>
488
+ <a name='L423'></a><a href='#L423'>423</a>
489
+ <a name='L424'></a><a href='#L424'>424</a>
490
+ <a name='L425'></a><a href='#L425'>425</a>
491
+ <a name='L426'></a><a href='#L426'>426</a>
492
+ <a name='L427'></a><a href='#L427'>427</a>
493
+ <a name='L428'></a><a href='#L428'>428</a>
494
+ <a name='L429'></a><a href='#L429'>429</a>
495
+ <a name='L430'></a><a href='#L430'>430</a>
496
+ <a name='L431'></a><a href='#L431'>431</a>
497
+ <a name='L432'></a><a href='#L432'>432</a>
498
+ <a name='L433'></a><a href='#L433'>433</a>
499
+ <a name='L434'></a><a href='#L434'>434</a>
500
+ <a name='L435'></a><a href='#L435'>435</a>
501
+ <a name='L436'></a><a href='#L436'>436</a>
502
+ <a name='L437'></a><a href='#L437'>437</a>
503
+ <a name='L438'></a><a href='#L438'>438</a>
504
+ <a name='L439'></a><a href='#L439'>439</a>
505
+ <a name='L440'></a><a href='#L440'>440</a>
506
+ <a name='L441'></a><a href='#L441'>441</a>
507
+ <a name='L442'></a><a href='#L442'>442</a>
508
+ <a name='L443'></a><a href='#L443'>443</a>
509
+ <a name='L444'></a><a href='#L444'>444</a>
510
+ <a name='L445'></a><a href='#L445'>445</a>
511
+ <a name='L446'></a><a href='#L446'>446</a>
512
+ <a name='L447'></a><a href='#L447'>447</a>
513
+ <a name='L448'></a><a href='#L448'>448</a>
514
+ <a name='L449'></a><a href='#L449'>449</a>
515
+ <a name='L450'></a><a href='#L450'>450</a>
516
+ <a name='L451'></a><a href='#L451'>451</a>
517
+ <a name='L452'></a><a href='#L452'>452</a>
518
+ <a name='L453'></a><a href='#L453'>453</a>
519
+ <a name='L454'></a><a href='#L454'>454</a>
520
+ <a name='L455'></a><a href='#L455'>455</a>
521
+ <a name='L456'></a><a href='#L456'>456</a>
522
+ <a name='L457'></a><a href='#L457'>457</a>
523
+ <a name='L458'></a><a href='#L458'>458</a>
524
+ <a name='L459'></a><a href='#L459'>459</a>
525
+ <a name='L460'></a><a href='#L460'>460</a>
526
+ <a name='L461'></a><a href='#L461'>461</a>
527
+ <a name='L462'></a><a href='#L462'>462</a>
528
+ <a name='L463'></a><a href='#L463'>463</a>
529
+ <a name='L464'></a><a href='#L464'>464</a>
530
+ <a name='L465'></a><a href='#L465'>465</a>
531
+ <a name='L466'></a><a href='#L466'>466</a>
532
+ <a name='L467'></a><a href='#L467'>467</a>
533
+ <a name='L468'></a><a href='#L468'>468</a>
534
+ <a name='L469'></a><a href='#L469'>469</a>
535
+ <a name='L470'></a><a href='#L470'>470</a>
536
+ <a name='L471'></a><a href='#L471'>471</a>
537
+ <a name='L472'></a><a href='#L472'>472</a>
538
+ <a name='L473'></a><a href='#L473'>473</a>
539
+ <a name='L474'></a><a href='#L474'>474</a>
540
+ <a name='L475'></a><a href='#L475'>475</a>
541
+ <a name='L476'></a><a href='#L476'>476</a>
542
+ <a name='L477'></a><a href='#L477'>477</a>
543
+ <a name='L478'></a><a href='#L478'>478</a>
544
+ <a name='L479'></a><a href='#L479'>479</a>
545
+ <a name='L480'></a><a href='#L480'>480</a>
546
+ <a name='L481'></a><a href='#L481'>481</a>
547
+ <a name='L482'></a><a href='#L482'>482</a>
548
+ <a name='L483'></a><a href='#L483'>483</a>
549
+ <a name='L484'></a><a href='#L484'>484</a>
550
+ <a name='L485'></a><a href='#L485'>485</a>
551
+ <a name='L486'></a><a href='#L486'>486</a>
552
+ <a name='L487'></a><a href='#L487'>487</a>
553
+ <a name='L488'></a><a href='#L488'>488</a>
554
+ <a name='L489'></a><a href='#L489'>489</a>
555
+ <a name='L490'></a><a href='#L490'>490</a>
556
+ <a name='L491'></a><a href='#L491'>491</a>
557
+ <a name='L492'></a><a href='#L492'>492</a>
558
+ <a name='L493'></a><a href='#L493'>493</a>
559
+ <a name='L494'></a><a href='#L494'>494</a>
560
+ <a name='L495'></a><a href='#L495'>495</a>
561
+ <a name='L496'></a><a href='#L496'>496</a>
562
+ <a name='L497'></a><a href='#L497'>497</a>
563
+ <a name='L498'></a><a href='#L498'>498</a>
564
+ <a name='L499'></a><a href='#L499'>499</a>
565
+ <a name='L500'></a><a href='#L500'>500</a>
566
+ <a name='L501'></a><a href='#L501'>501</a>
567
+ <a name='L502'></a><a href='#L502'>502</a>
568
+ <a name='L503'></a><a href='#L503'>503</a>
569
+ <a name='L504'></a><a href='#L504'>504</a>
570
+ <a name='L505'></a><a href='#L505'>505</a>
571
+ <a name='L506'></a><a href='#L506'>506</a>
572
+ <a name='L507'></a><a href='#L507'>507</a>
573
+ <a name='L508'></a><a href='#L508'>508</a>
574
+ <a name='L509'></a><a href='#L509'>509</a>
575
+ <a name='L510'></a><a href='#L510'>510</a>
576
+ <a name='L511'></a><a href='#L511'>511</a>
577
+ <a name='L512'></a><a href='#L512'>512</a>
578
+ <a name='L513'></a><a href='#L513'>513</a>
579
+ <a name='L514'></a><a href='#L514'>514</a>
580
+ <a name='L515'></a><a href='#L515'>515</a>
581
+ <a name='L516'></a><a href='#L516'>516</a>
582
+ <a name='L517'></a><a href='#L517'>517</a>
583
+ <a name='L518'></a><a href='#L518'>518</a>
584
+ <a name='L519'></a><a href='#L519'>519</a>
585
+ <a name='L520'></a><a href='#L520'>520</a>
586
+ <a name='L521'></a><a href='#L521'>521</a>
587
+ <a name='L522'></a><a href='#L522'>522</a>
588
+ <a name='L523'></a><a href='#L523'>523</a>
589
+ <a name='L524'></a><a href='#L524'>524</a>
590
+ <a name='L525'></a><a href='#L525'>525</a>
591
+ <a name='L526'></a><a href='#L526'>526</a>
592
+ <a name='L527'></a><a href='#L527'>527</a>
593
+ <a name='L528'></a><a href='#L528'>528</a>
594
+ <a name='L529'></a><a href='#L529'>529</a>
595
+ <a name='L530'></a><a href='#L530'>530</a>
596
+ <a name='L531'></a><a href='#L531'>531</a>
597
+ <a name='L532'></a><a href='#L532'>532</a>
598
+ <a name='L533'></a><a href='#L533'>533</a>
599
+ <a name='L534'></a><a href='#L534'>534</a>
600
+ <a name='L535'></a><a href='#L535'>535</a>
601
+ <a name='L536'></a><a href='#L536'>536</a>
602
+ <a name='L537'></a><a href='#L537'>537</a>
603
+ <a name='L538'></a><a href='#L538'>538</a>
604
+ <a name='L539'></a><a href='#L539'>539</a>
605
+ <a name='L540'></a><a href='#L540'>540</a>
606
+ <a name='L541'></a><a href='#L541'>541</a>
607
+ <a name='L542'></a><a href='#L542'>542</a>
608
+ <a name='L543'></a><a href='#L543'>543</a>
609
+ <a name='L544'></a><a href='#L544'>544</a>
610
+ <a name='L545'></a><a href='#L545'>545</a>
611
+ <a name='L546'></a><a href='#L546'>546</a>
612
+ <a name='L547'></a><a href='#L547'>547</a>
613
+ <a name='L548'></a><a href='#L548'>548</a>
614
+ <a name='L549'></a><a href='#L549'>549</a>
615
+ <a name='L550'></a><a href='#L550'>550</a>
616
+ <a name='L551'></a><a href='#L551'>551</a>
617
+ <a name='L552'></a><a href='#L552'>552</a>
618
+ <a name='L553'></a><a href='#L553'>553</a>
619
+ <a name='L554'></a><a href='#L554'>554</a>
620
+ <a name='L555'></a><a href='#L555'>555</a>
621
+ <a name='L556'></a><a href='#L556'>556</a>
622
+ <a name='L557'></a><a href='#L557'>557</a>
623
+ <a name='L558'></a><a href='#L558'>558</a>
624
+ <a name='L559'></a><a href='#L559'>559</a>
625
+ <a name='L560'></a><a href='#L560'>560</a>
626
+ <a name='L561'></a><a href='#L561'>561</a>
627
+ <a name='L562'></a><a href='#L562'>562</a>
628
+ <a name='L563'></a><a href='#L563'>563</a>
629
+ <a name='L564'></a><a href='#L564'>564</a>
630
+ <a name='L565'></a><a href='#L565'>565</a>
631
+ <a name='L566'></a><a href='#L566'>566</a>
632
+ <a name='L567'></a><a href='#L567'>567</a>
633
+ <a name='L568'></a><a href='#L568'>568</a>
634
+ <a name='L569'></a><a href='#L569'>569</a>
635
+ <a name='L570'></a><a href='#L570'>570</a>
636
+ <a name='L571'></a><a href='#L571'>571</a>
637
+ <a name='L572'></a><a href='#L572'>572</a>
638
+ <a name='L573'></a><a href='#L573'>573</a>
639
+ <a name='L574'></a><a href='#L574'>574</a>
640
+ <a name='L575'></a><a href='#L575'>575</a>
641
+ <a name='L576'></a><a href='#L576'>576</a>
642
+ <a name='L577'></a><a href='#L577'>577</a>
643
+ <a name='L578'></a><a href='#L578'>578</a>
644
+ <a name='L579'></a><a href='#L579'>579</a>
645
+ <a name='L580'></a><a href='#L580'>580</a>
646
+ <a name='L581'></a><a href='#L581'>581</a>
647
+ <a name='L582'></a><a href='#L582'>582</a>
648
+ <a name='L583'></a><a href='#L583'>583</a>
649
+ <a name='L584'></a><a href='#L584'>584</a>
650
+ <a name='L585'></a><a href='#L585'>585</a>
651
+ <a name='L586'></a><a href='#L586'>586</a>
652
+ <a name='L587'></a><a href='#L587'>587</a>
653
+ <a name='L588'></a><a href='#L588'>588</a>
654
+ <a name='L589'></a><a href='#L589'>589</a>
655
+ <a name='L590'></a><a href='#L590'>590</a>
656
+ <a name='L591'></a><a href='#L591'>591</a>
657
+ <a name='L592'></a><a href='#L592'>592</a>
658
+ <a name='L593'></a><a href='#L593'>593</a>
659
+ <a name='L594'></a><a href='#L594'>594</a>
660
+ <a name='L595'></a><a href='#L595'>595</a>
661
+ <a name='L596'></a><a href='#L596'>596</a>
662
+ <a name='L597'></a><a href='#L597'>597</a>
663
+ <a name='L598'></a><a href='#L598'>598</a>
664
+ <a name='L599'></a><a href='#L599'>599</a>
665
+ <a name='L600'></a><a href='#L600'>600</a>
666
+ <a name='L601'></a><a href='#L601'>601</a>
667
+ <a name='L602'></a><a href='#L602'>602</a>
668
+ <a name='L603'></a><a href='#L603'>603</a>
669
+ <a name='L604'></a><a href='#L604'>604</a>
670
+ <a name='L605'></a><a href='#L605'>605</a>
671
+ <a name='L606'></a><a href='#L606'>606</a>
672
+ <a name='L607'></a><a href='#L607'>607</a>
673
+ <a name='L608'></a><a href='#L608'>608</a>
674
+ <a name='L609'></a><a href='#L609'>609</a>
675
+ <a name='L610'></a><a href='#L610'>610</a>
676
+ <a name='L611'></a><a href='#L611'>611</a>
677
+ <a name='L612'></a><a href='#L612'>612</a>
678
+ <a name='L613'></a><a href='#L613'>613</a>
679
+ <a name='L614'></a><a href='#L614'>614</a>
680
+ <a name='L615'></a><a href='#L615'>615</a>
681
+ <a name='L616'></a><a href='#L616'>616</a>
682
+ <a name='L617'></a><a href='#L617'>617</a>
683
+ <a name='L618'></a><a href='#L618'>618</a>
684
+ <a name='L619'></a><a href='#L619'>619</a>
685
+ <a name='L620'></a><a href='#L620'>620</a>
686
+ <a name='L621'></a><a href='#L621'>621</a>
687
+ <a name='L622'></a><a href='#L622'>622</a>
688
+ <a name='L623'></a><a href='#L623'>623</a>
689
+ <a name='L624'></a><a href='#L624'>624</a>
690
+ <a name='L625'></a><a href='#L625'>625</a>
691
+ <a name='L626'></a><a href='#L626'>626</a>
692
+ <a name='L627'></a><a href='#L627'>627</a>
693
+ <a name='L628'></a><a href='#L628'>628</a>
694
+ <a name='L629'></a><a href='#L629'>629</a>
695
+ <a name='L630'></a><a href='#L630'>630</a>
696
+ <a name='L631'></a><a href='#L631'>631</a>
697
+ <a name='L632'></a><a href='#L632'>632</a>
698
+ <a name='L633'></a><a href='#L633'>633</a>
699
+ <a name='L634'></a><a href='#L634'>634</a>
700
+ <a name='L635'></a><a href='#L635'>635</a>
701
+ <a name='L636'></a><a href='#L636'>636</a>
702
+ <a name='L637'></a><a href='#L637'>637</a>
703
+ <a name='L638'></a><a href='#L638'>638</a>
704
+ <a name='L639'></a><a href='#L639'>639</a>
705
+ <a name='L640'></a><a href='#L640'>640</a>
706
+ <a name='L641'></a><a href='#L641'>641</a>
707
+ <a name='L642'></a><a href='#L642'>642</a>
708
+ <a name='L643'></a><a href='#L643'>643</a>
709
+ <a name='L644'></a><a href='#L644'>644</a>
710
+ <a name='L645'></a><a href='#L645'>645</a>
711
+ <a name='L646'></a><a href='#L646'>646</a>
712
+ <a name='L647'></a><a href='#L647'>647</a>
713
+ <a name='L648'></a><a href='#L648'>648</a>
714
+ <a name='L649'></a><a href='#L649'>649</a>
715
+ <a name='L650'></a><a href='#L650'>650</a>
716
+ <a name='L651'></a><a href='#L651'>651</a>
717
+ <a name='L652'></a><a href='#L652'>652</a>
718
+ <a name='L653'></a><a href='#L653'>653</a>
719
+ <a name='L654'></a><a href='#L654'>654</a>
720
+ <a name='L655'></a><a href='#L655'>655</a>
721
+ <a name='L656'></a><a href='#L656'>656</a>
722
+ <a name='L657'></a><a href='#L657'>657</a>
723
+ <a name='L658'></a><a href='#L658'>658</a>
724
+ <a name='L659'></a><a href='#L659'>659</a>
725
+ <a name='L660'></a><a href='#L660'>660</a>
726
+ <a name='L661'></a><a href='#L661'>661</a>
727
+ <a name='L662'></a><a href='#L662'>662</a>
728
+ <a name='L663'></a><a href='#L663'>663</a>
729
+ <a name='L664'></a><a href='#L664'>664</a>
730
+ <a name='L665'></a><a href='#L665'>665</a>
731
+ <a name='L666'></a><a href='#L666'>666</a>
732
+ <a name='L667'></a><a href='#L667'>667</a>
733
+ <a name='L668'></a><a href='#L668'>668</a>
734
+ <a name='L669'></a><a href='#L669'>669</a>
735
+ <a name='L670'></a><a href='#L670'>670</a>
736
+ <a name='L671'></a><a href='#L671'>671</a>
737
+ <a name='L672'></a><a href='#L672'>672</a>
738
+ <a name='L673'></a><a href='#L673'>673</a>
739
+ <a name='L674'></a><a href='#L674'>674</a>
740
+ <a name='L675'></a><a href='#L675'>675</a>
741
+ <a name='L676'></a><a href='#L676'>676</a>
742
+ <a name='L677'></a><a href='#L677'>677</a>
743
+ <a name='L678'></a><a href='#L678'>678</a>
744
+ <a name='L679'></a><a href='#L679'>679</a>
745
+ <a name='L680'></a><a href='#L680'>680</a>
746
+ <a name='L681'></a><a href='#L681'>681</a>
747
+ <a name='L682'></a><a href='#L682'>682</a>
748
+ <a name='L683'></a><a href='#L683'>683</a>
749
+ <a name='L684'></a><a href='#L684'>684</a>
750
+ <a name='L685'></a><a href='#L685'>685</a>
751
+ <a name='L686'></a><a href='#L686'>686</a>
752
+ <a name='L687'></a><a href='#L687'>687</a>
753
+ <a name='L688'></a><a href='#L688'>688</a>
754
+ <a name='L689'></a><a href='#L689'>689</a>
755
+ <a name='L690'></a><a href='#L690'>690</a>
756
+ <a name='L691'></a><a href='#L691'>691</a>
757
+ <a name='L692'></a><a href='#L692'>692</a>
758
+ <a name='L693'></a><a href='#L693'>693</a>
759
+ <a name='L694'></a><a href='#L694'>694</a>
760
+ <a name='L695'></a><a href='#L695'>695</a>
761
+ <a name='L696'></a><a href='#L696'>696</a>
762
+ <a name='L697'></a><a href='#L697'>697</a>
763
+ <a name='L698'></a><a href='#L698'>698</a>
764
+ <a name='L699'></a><a href='#L699'>699</a>
765
+ <a name='L700'></a><a href='#L700'>700</a>
766
+ <a name='L701'></a><a href='#L701'>701</a>
767
+ <a name='L702'></a><a href='#L702'>702</a>
768
+ <a name='L703'></a><a href='#L703'>703</a>
769
+ <a name='L704'></a><a href='#L704'>704</a>
770
+ <a name='L705'></a><a href='#L705'>705</a>
771
+ <a name='L706'></a><a href='#L706'>706</a>
772
+ <a name='L707'></a><a href='#L707'>707</a>
773
+ <a name='L708'></a><a href='#L708'>708</a>
774
+ <a name='L709'></a><a href='#L709'>709</a>
775
+ <a name='L710'></a><a href='#L710'>710</a>
776
+ <a name='L711'></a><a href='#L711'>711</a>
777
+ <a name='L712'></a><a href='#L712'>712</a>
778
+ <a name='L713'></a><a href='#L713'>713</a>
779
+ <a name='L714'></a><a href='#L714'>714</a>
780
+ <a name='L715'></a><a href='#L715'>715</a>
781
+ <a name='L716'></a><a href='#L716'>716</a>
782
+ <a name='L717'></a><a href='#L717'>717</a>
783
+ <a name='L718'></a><a href='#L718'>718</a>
784
+ <a name='L719'></a><a href='#L719'>719</a>
785
+ <a name='L720'></a><a href='#L720'>720</a>
786
+ <a name='L721'></a><a href='#L721'>721</a>
787
+ <a name='L722'></a><a href='#L722'>722</a>
788
+ <a name='L723'></a><a href='#L723'>723</a>
789
+ <a name='L724'></a><a href='#L724'>724</a>
790
+ <a name='L725'></a><a href='#L725'>725</a>
791
+ <a name='L726'></a><a href='#L726'>726</a>
792
+ <a name='L727'></a><a href='#L727'>727</a>
793
+ <a name='L728'></a><a href='#L728'>728</a>
794
+ <a name='L729'></a><a href='#L729'>729</a>
795
+ <a name='L730'></a><a href='#L730'>730</a>
796
+ <a name='L731'></a><a href='#L731'>731</a>
797
+ <a name='L732'></a><a href='#L732'>732</a>
798
+ <a name='L733'></a><a href='#L733'>733</a>
799
+ <a name='L734'></a><a href='#L734'>734</a>
800
+ <a name='L735'></a><a href='#L735'>735</a>
801
+ <a name='L736'></a><a href='#L736'>736</a>
802
+ <a name='L737'></a><a href='#L737'>737</a>
803
+ <a name='L738'></a><a href='#L738'>738</a>
804
+ <a name='L739'></a><a href='#L739'>739</a>
805
+ <a name='L740'></a><a href='#L740'>740</a>
806
+ <a name='L741'></a><a href='#L741'>741</a>
807
+ <a name='L742'></a><a href='#L742'>742</a>
808
+ <a name='L743'></a><a href='#L743'>743</a>
809
+ <a name='L744'></a><a href='#L744'>744</a>
810
+ <a name='L745'></a><a href='#L745'>745</a>
811
+ <a name='L746'></a><a href='#L746'>746</a>
812
+ <a name='L747'></a><a href='#L747'>747</a>
813
+ <a name='L748'></a><a href='#L748'>748</a>
814
+ <a name='L749'></a><a href='#L749'>749</a>
815
+ <a name='L750'></a><a href='#L750'>750</a>
816
+ <a name='L751'></a><a href='#L751'>751</a>
817
+ <a name='L752'></a><a href='#L752'>752</a>
818
+ <a name='L753'></a><a href='#L753'>753</a>
819
+ <a name='L754'></a><a href='#L754'>754</a>
820
+ <a name='L755'></a><a href='#L755'>755</a>
821
+ <a name='L756'></a><a href='#L756'>756</a>
822
+ <a name='L757'></a><a href='#L757'>757</a>
823
+ <a name='L758'></a><a href='#L758'>758</a>
824
+ <a name='L759'></a><a href='#L759'>759</a>
825
+ <a name='L760'></a><a href='#L760'>760</a>
826
+ <a name='L761'></a><a href='#L761'>761</a>
827
+ <a name='L762'></a><a href='#L762'>762</a>
828
+ <a name='L763'></a><a href='#L763'>763</a>
829
+ <a name='L764'></a><a href='#L764'>764</a>
830
+ <a name='L765'></a><a href='#L765'>765</a>
831
+ <a name='L766'></a><a href='#L766'>766</a>
832
+ <a name='L767'></a><a href='#L767'>767</a>
833
+ <a name='L768'></a><a href='#L768'>768</a>
834
+ <a name='L769'></a><a href='#L769'>769</a>
835
+ <a name='L770'></a><a href='#L770'>770</a>
836
+ <a name='L771'></a><a href='#L771'>771</a>
837
+ <a name='L772'></a><a href='#L772'>772</a>
838
+ <a name='L773'></a><a href='#L773'>773</a>
839
+ <a name='L774'></a><a href='#L774'>774</a>
840
+ <a name='L775'></a><a href='#L775'>775</a>
841
+ <a name='L776'></a><a href='#L776'>776</a>
842
+ <a name='L777'></a><a href='#L777'>777</a>
843
+ <a name='L778'></a><a href='#L778'>778</a>
844
+ <a name='L779'></a><a href='#L779'>779</a>
845
+ <a name='L780'></a><a href='#L780'>780</a>
846
+ <a name='L781'></a><a href='#L781'>781</a>
847
+ <a name='L782'></a><a href='#L782'>782</a>
848
+ <a name='L783'></a><a href='#L783'>783</a>
849
+ <a name='L784'></a><a href='#L784'>784</a>
850
+ <a name='L785'></a><a href='#L785'>785</a>
851
+ <a name='L786'></a><a href='#L786'>786</a>
852
+ <a name='L787'></a><a href='#L787'>787</a>
853
+ <a name='L788'></a><a href='#L788'>788</a>
854
+ <a name='L789'></a><a href='#L789'>789</a>
855
+ <a name='L790'></a><a href='#L790'>790</a>
856
+ <a name='L791'></a><a href='#L791'>791</a>
857
+ <a name='L792'></a><a href='#L792'>792</a>
858
+ <a name='L793'></a><a href='#L793'>793</a>
859
+ <a name='L794'></a><a href='#L794'>794</a>
860
+ <a name='L795'></a><a href='#L795'>795</a>
861
+ <a name='L796'></a><a href='#L796'>796</a>
862
+ <a name='L797'></a><a href='#L797'>797</a>
863
+ <a name='L798'></a><a href='#L798'>798</a>
864
+ <a name='L799'></a><a href='#L799'>799</a>
865
+ <a name='L800'></a><a href='#L800'>800</a>
866
+ <a name='L801'></a><a href='#L801'>801</a>
867
+ <a name='L802'></a><a href='#L802'>802</a>
868
+ <a name='L803'></a><a href='#L803'>803</a>
869
+ <a name='L804'></a><a href='#L804'>804</a>
870
+ <a name='L805'></a><a href='#L805'>805</a>
871
+ <a name='L806'></a><a href='#L806'>806</a>
872
+ <a name='L807'></a><a href='#L807'>807</a>
873
+ <a name='L808'></a><a href='#L808'>808</a>
874
+ <a name='L809'></a><a href='#L809'>809</a>
875
+ <a name='L810'></a><a href='#L810'>810</a>
876
+ <a name='L811'></a><a href='#L811'>811</a>
877
+ <a name='L812'></a><a href='#L812'>812</a>
878
+ <a name='L813'></a><a href='#L813'>813</a>
879
+ <a name='L814'></a><a href='#L814'>814</a>
880
+ <a name='L815'></a><a href='#L815'>815</a>
881
+ <a name='L816'></a><a href='#L816'>816</a>
882
+ <a name='L817'></a><a href='#L817'>817</a>
883
+ <a name='L818'></a><a href='#L818'>818</a>
884
+ <a name='L819'></a><a href='#L819'>819</a>
885
+ <a name='L820'></a><a href='#L820'>820</a>
886
+ <a name='L821'></a><a href='#L821'>821</a>
887
+ <a name='L822'></a><a href='#L822'>822</a>
888
+ <a name='L823'></a><a href='#L823'>823</a>
889
+ <a name='L824'></a><a href='#L824'>824</a>
890
+ <a name='L825'></a><a href='#L825'>825</a>
891
+ <a name='L826'></a><a href='#L826'>826</a>
892
+ <a name='L827'></a><a href='#L827'>827</a>
893
+ <a name='L828'></a><a href='#L828'>828</a>
894
+ <a name='L829'></a><a href='#L829'>829</a>
895
+ <a name='L830'></a><a href='#L830'>830</a>
896
+ <a name='L831'></a><a href='#L831'>831</a>
897
+ <a name='L832'></a><a href='#L832'>832</a>
898
+ <a name='L833'></a><a href='#L833'>833</a>
899
+ <a name='L834'></a><a href='#L834'>834</a>
900
+ <a name='L835'></a><a href='#L835'>835</a>
901
+ <a name='L836'></a><a href='#L836'>836</a>
902
+ <a name='L837'></a><a href='#L837'>837</a>
903
+ <a name='L838'></a><a href='#L838'>838</a>
904
+ <a name='L839'></a><a href='#L839'>839</a>
905
+ <a name='L840'></a><a href='#L840'>840</a>
906
+ <a name='L841'></a><a href='#L841'>841</a>
907
+ <a name='L842'></a><a href='#L842'>842</a>
908
+ <a name='L843'></a><a href='#L843'>843</a>
909
+ <a name='L844'></a><a href='#L844'>844</a>
910
+ <a name='L845'></a><a href='#L845'>845</a>
911
+ <a name='L846'></a><a href='#L846'>846</a>
912
+ <a name='L847'></a><a href='#L847'>847</a>
913
+ <a name='L848'></a><a href='#L848'>848</a>
914
+ <a name='L849'></a><a href='#L849'>849</a>
915
+ <a name='L850'></a><a href='#L850'>850</a>
916
+ <a name='L851'></a><a href='#L851'>851</a>
917
+ <a name='L852'></a><a href='#L852'>852</a>
918
+ <a name='L853'></a><a href='#L853'>853</a>
919
+ <a name='L854'></a><a href='#L854'>854</a>
920
+ <a name='L855'></a><a href='#L855'>855</a>
921
+ <a name='L856'></a><a href='#L856'>856</a>
922
+ <a name='L857'></a><a href='#L857'>857</a>
923
+ <a name='L858'></a><a href='#L858'>858</a>
924
+ <a name='L859'></a><a href='#L859'>859</a>
925
+ <a name='L860'></a><a href='#L860'>860</a>
926
+ <a name='L861'></a><a href='#L861'>861</a>
927
+ <a name='L862'></a><a href='#L862'>862</a>
928
+ <a name='L863'></a><a href='#L863'>863</a>
929
+ <a name='L864'></a><a href='#L864'>864</a>
930
+ <a name='L865'></a><a href='#L865'>865</a>
931
+ <a name='L866'></a><a href='#L866'>866</a>
932
+ <a name='L867'></a><a href='#L867'>867</a>
933
+ <a name='L868'></a><a href='#L868'>868</a>
934
+ <a name='L869'></a><a href='#L869'>869</a>
935
+ <a name='L870'></a><a href='#L870'>870</a>
936
+ <a name='L871'></a><a href='#L871'>871</a>
937
+ <a name='L872'></a><a href='#L872'>872</a>
938
+ <a name='L873'></a><a href='#L873'>873</a>
939
+ <a name='L874'></a><a href='#L874'>874</a>
940
+ <a name='L875'></a><a href='#L875'>875</a>
941
+ <a name='L876'></a><a href='#L876'>876</a>
942
+ <a name='L877'></a><a href='#L877'>877</a>
943
+ <a name='L878'></a><a href='#L878'>878</a>
944
+ <a name='L879'></a><a href='#L879'>879</a>
945
+ <a name='L880'></a><a href='#L880'>880</a>
946
+ <a name='L881'></a><a href='#L881'>881</a>
947
+ <a name='L882'></a><a href='#L882'>882</a>
948
+ <a name='L883'></a><a href='#L883'>883</a>
949
+ <a name='L884'></a><a href='#L884'>884</a>
950
+ <a name='L885'></a><a href='#L885'>885</a>
951
+ <a name='L886'></a><a href='#L886'>886</a>
952
+ <a name='L887'></a><a href='#L887'>887</a>
953
+ <a name='L888'></a><a href='#L888'>888</a>
954
+ <a name='L889'></a><a href='#L889'>889</a>
955
+ <a name='L890'></a><a href='#L890'>890</a>
956
+ <a name='L891'></a><a href='#L891'>891</a>
957
+ <a name='L892'></a><a href='#L892'>892</a>
958
+ <a name='L893'></a><a href='#L893'>893</a>
959
+ <a name='L894'></a><a href='#L894'>894</a>
960
+ <a name='L895'></a><a href='#L895'>895</a>
961
+ <a name='L896'></a><a href='#L896'>896</a>
962
+ <a name='L897'></a><a href='#L897'>897</a>
963
+ <a name='L898'></a><a href='#L898'>898</a>
964
+ <a name='L899'></a><a href='#L899'>899</a>
965
+ <a name='L900'></a><a href='#L900'>900</a>
966
+ <a name='L901'></a><a href='#L901'>901</a>
967
+ <a name='L902'></a><a href='#L902'>902</a>
968
+ <a name='L903'></a><a href='#L903'>903</a>
969
+ <a name='L904'></a><a href='#L904'>904</a>
970
+ <a name='L905'></a><a href='#L905'>905</a>
971
+ <a name='L906'></a><a href='#L906'>906</a>
972
+ <a name='L907'></a><a href='#L907'>907</a>
973
+ <a name='L908'></a><a href='#L908'>908</a>
974
+ <a name='L909'></a><a href='#L909'>909</a>
975
+ <a name='L910'></a><a href='#L910'>910</a>
976
+ <a name='L911'></a><a href='#L911'>911</a>
977
+ <a name='L912'></a><a href='#L912'>912</a>
978
+ <a name='L913'></a><a href='#L913'>913</a>
979
+ <a name='L914'></a><a href='#L914'>914</a>
980
+ <a name='L915'></a><a href='#L915'>915</a>
981
+ <a name='L916'></a><a href='#L916'>916</a>
982
+ <a name='L917'></a><a href='#L917'>917</a>
983
+ <a name='L918'></a><a href='#L918'>918</a>
984
+ <a name='L919'></a><a href='#L919'>919</a>
985
+ <a name='L920'></a><a href='#L920'>920</a>
986
+ <a name='L921'></a><a href='#L921'>921</a>
987
+ <a name='L922'></a><a href='#L922'>922</a>
988
+ <a name='L923'></a><a href='#L923'>923</a>
989
+ <a name='L924'></a><a href='#L924'>924</a>
990
+ <a name='L925'></a><a href='#L925'>925</a>
991
+ <a name='L926'></a><a href='#L926'>926</a>
992
+ <a name='L927'></a><a href='#L927'>927</a>
993
+ <a name='L928'></a><a href='#L928'>928</a>
994
+ <a name='L929'></a><a href='#L929'>929</a>
995
+ <a name='L930'></a><a href='#L930'>930</a>
996
+ <a name='L931'></a><a href='#L931'>931</a>
997
+ <a name='L932'></a><a href='#L932'>932</a>
998
+ <a name='L933'></a><a href='#L933'>933</a>
999
+ <a name='L934'></a><a href='#L934'>934</a>
1000
+ <a name='L935'></a><a href='#L935'>935</a>
1001
+ <a name='L936'></a><a href='#L936'>936</a>
1002
+ <a name='L937'></a><a href='#L937'>937</a>
1003
+ <a name='L938'></a><a href='#L938'>938</a>
1004
+ <a name='L939'></a><a href='#L939'>939</a>
1005
+ <a name='L940'></a><a href='#L940'>940</a>
1006
+ <a name='L941'></a><a href='#L941'>941</a>
1007
+ <a name='L942'></a><a href='#L942'>942</a>
1008
+ <a name='L943'></a><a href='#L943'>943</a>
1009
+ <a name='L944'></a><a href='#L944'>944</a>
1010
+ <a name='L945'></a><a href='#L945'>945</a>
1011
+ <a name='L946'></a><a href='#L946'>946</a>
1012
+ <a name='L947'></a><a href='#L947'>947</a>
1013
+ <a name='L948'></a><a href='#L948'>948</a>
1014
+ <a name='L949'></a><a href='#L949'>949</a>
1015
+ <a name='L950'></a><a href='#L950'>950</a>
1016
+ <a name='L951'></a><a href='#L951'>951</a>
1017
+ <a name='L952'></a><a href='#L952'>952</a>
1018
+ <a name='L953'></a><a href='#L953'>953</a>
1019
+ <a name='L954'></a><a href='#L954'>954</a>
1020
+ <a name='L955'></a><a href='#L955'>955</a>
1021
+ <a name='L956'></a><a href='#L956'>956</a>
1022
+ <a name='L957'></a><a href='#L957'>957</a>
1023
+ <a name='L958'></a><a href='#L958'>958</a>
1024
+ <a name='L959'></a><a href='#L959'>959</a>
1025
+ <a name='L960'></a><a href='#L960'>960</a>
1026
+ <a name='L961'></a><a href='#L961'>961</a>
1027
+ <a name='L962'></a><a href='#L962'>962</a>
1028
+ <a name='L963'></a><a href='#L963'>963</a>
1029
+ <a name='L964'></a><a href='#L964'>964</a>
1030
+ <a name='L965'></a><a href='#L965'>965</a>
1031
+ <a name='L966'></a><a href='#L966'>966</a>
1032
+ <a name='L967'></a><a href='#L967'>967</a>
1033
+ <a name='L968'></a><a href='#L968'>968</a>
1034
+ <a name='L969'></a><a href='#L969'>969</a>
1035
+ <a name='L970'></a><a href='#L970'>970</a>
1036
+ <a name='L971'></a><a href='#L971'>971</a>
1037
+ <a name='L972'></a><a href='#L972'>972</a>
1038
+ <a name='L973'></a><a href='#L973'>973</a>
1039
+ <a name='L974'></a><a href='#L974'>974</a>
1040
+ <a name='L975'></a><a href='#L975'>975</a>
1041
+ <a name='L976'></a><a href='#L976'>976</a>
1042
+ <a name='L977'></a><a href='#L977'>977</a>
1043
+ <a name='L978'></a><a href='#L978'>978</a>
1044
+ <a name='L979'></a><a href='#L979'>979</a>
1045
+ <a name='L980'></a><a href='#L980'>980</a>
1046
+ <a name='L981'></a><a href='#L981'>981</a>
1047
+ <a name='L982'></a><a href='#L982'>982</a>
1048
+ <a name='L983'></a><a href='#L983'>983</a>
1049
+ <a name='L984'></a><a href='#L984'>984</a>
1050
+ <a name='L985'></a><a href='#L985'>985</a>
1051
+ <a name='L986'></a><a href='#L986'>986</a>
1052
+ <a name='L987'></a><a href='#L987'>987</a>
1053
+ <a name='L988'></a><a href='#L988'>988</a>
1054
+ <a name='L989'></a><a href='#L989'>989</a>
1055
+ <a name='L990'></a><a href='#L990'>990</a>
1056
+ <a name='L991'></a><a href='#L991'>991</a>
1057
+ <a name='L992'></a><a href='#L992'>992</a>
1058
+ <a name='L993'></a><a href='#L993'>993</a>
1059
+ <a name='L994'></a><a href='#L994'>994</a>
1060
+ <a name='L995'></a><a href='#L995'>995</a>
1061
+ <a name='L996'></a><a href='#L996'>996</a>
1062
+ <a name='L997'></a><a href='#L997'>997</a></td><td class="line-coverage quiet"><span class="cline-any cline-yes">1x</span>
1063
+ <span class="cline-any cline-yes">1x</span>
1064
+ <span class="cline-any cline-yes">1x</span>
1065
+ <span class="cline-any cline-yes">1x</span>
1066
+ <span class="cline-any cline-yes">1x</span>
1067
+ <span class="cline-any cline-yes">1x</span>
1068
+ <span class="cline-any cline-neutral">&nbsp;</span>
1069
+ <span class="cline-any cline-neutral">&nbsp;</span>
1070
+ <span class="cline-any cline-neutral">&nbsp;</span>
1071
+ <span class="cline-any cline-neutral">&nbsp;</span>
1072
+ <span class="cline-any cline-yes">1x</span>
1073
+ <span class="cline-any cline-yes">1x</span>
1074
+ <span class="cline-any cline-yes">1x</span>
1075
+ <span class="cline-any cline-yes">1x</span>
1076
+ <span class="cline-any cline-neutral">&nbsp;</span>
1077
+ <span class="cline-any cline-yes">1x</span>
1078
+ <span class="cline-any cline-neutral">&nbsp;</span>
1079
+ <span class="cline-any cline-yes">1x</span>
1080
+ <span class="cline-any cline-yes">1x</span>
1081
+ <span class="cline-any cline-yes">1x</span>
1082
+ <span class="cline-any cline-yes">1x</span>
1083
+ <span class="cline-any cline-yes">1x</span>
1084
+ <span class="cline-any cline-yes">1x</span>
1085
+ <span class="cline-any cline-yes">1x</span>
1086
+ <span class="cline-any cline-yes">1x</span>
1087
+ <span class="cline-any cline-yes">1x</span>
1088
+ <span class="cline-any cline-yes">1x</span>
1089
+ <span class="cline-any cline-no">&nbsp;</span>
1090
+ <span class="cline-any cline-no">&nbsp;</span>
1091
+ <span class="cline-any cline-neutral">&nbsp;</span>
1092
+ <span class="cline-any cline-neutral">&nbsp;</span>
1093
+ <span class="cline-any cline-no">&nbsp;</span>
1094
+ <span class="cline-any cline-no">&nbsp;</span>
1095
+ <span class="cline-any cline-no">&nbsp;</span>
1096
+ <span class="cline-any cline-no">&nbsp;</span>
1097
+ <span class="cline-any cline-no">&nbsp;</span>
1098
+ <span class="cline-any cline-no">&nbsp;</span>
1099
+ <span class="cline-any cline-no">&nbsp;</span>
1100
+ <span class="cline-any cline-no">&nbsp;</span>
1101
+ <span class="cline-any cline-no">&nbsp;</span>
1102
+ <span class="cline-any cline-no">&nbsp;</span>
1103
+ <span class="cline-any cline-no">&nbsp;</span>
1104
+ <span class="cline-any cline-no">&nbsp;</span>
1105
+ <span class="cline-any cline-no">&nbsp;</span>
1106
+ <span class="cline-any cline-no">&nbsp;</span>
1107
+ <span class="cline-any cline-no">&nbsp;</span>
1108
+ <span class="cline-any cline-no">&nbsp;</span>
1109
+ <span class="cline-any cline-no">&nbsp;</span>
1110
+ <span class="cline-any cline-no">&nbsp;</span>
1111
+ <span class="cline-any cline-no">&nbsp;</span>
1112
+ <span class="cline-any cline-no">&nbsp;</span>
1113
+ <span class="cline-any cline-no">&nbsp;</span>
1114
+ <span class="cline-any cline-no">&nbsp;</span>
1115
+ <span class="cline-any cline-no">&nbsp;</span>
1116
+ <span class="cline-any cline-no">&nbsp;</span>
1117
+ <span class="cline-any cline-no">&nbsp;</span>
1118
+ <span class="cline-any cline-no">&nbsp;</span>
1119
+ <span class="cline-any cline-no">&nbsp;</span>
1120
+ <span class="cline-any cline-no">&nbsp;</span>
1121
+ <span class="cline-any cline-no">&nbsp;</span>
1122
+ <span class="cline-any cline-no">&nbsp;</span>
1123
+ <span class="cline-any cline-no">&nbsp;</span>
1124
+ <span class="cline-any cline-no">&nbsp;</span>
1125
+ <span class="cline-any cline-no">&nbsp;</span>
1126
+ <span class="cline-any cline-no">&nbsp;</span>
1127
+ <span class="cline-any cline-no">&nbsp;</span>
1128
+ <span class="cline-any cline-no">&nbsp;</span>
1129
+ <span class="cline-any cline-neutral">&nbsp;</span>
1130
+ <span class="cline-any cline-no">&nbsp;</span>
1131
+ <span class="cline-any cline-no">&nbsp;</span>
1132
+ <span class="cline-any cline-no">&nbsp;</span>
1133
+ <span class="cline-any cline-no">&nbsp;</span>
1134
+ <span class="cline-any cline-no">&nbsp;</span>
1135
+ <span class="cline-any cline-no">&nbsp;</span>
1136
+ <span class="cline-any cline-neutral">&nbsp;</span>
1137
+ <span class="cline-any cline-neutral">&nbsp;</span>
1138
+ <span class="cline-any cline-no">&nbsp;</span>
1139
+ <span class="cline-any cline-no">&nbsp;</span>
1140
+ <span class="cline-any cline-no">&nbsp;</span>
1141
+ <span class="cline-any cline-no">&nbsp;</span>
1142
+ <span class="cline-any cline-no">&nbsp;</span>
1143
+ <span class="cline-any cline-no">&nbsp;</span>
1144
+ <span class="cline-any cline-no">&nbsp;</span>
1145
+ <span class="cline-any cline-no">&nbsp;</span>
1146
+ <span class="cline-any cline-neutral">&nbsp;</span>
1147
+ <span class="cline-any cline-neutral">&nbsp;</span>
1148
+ <span class="cline-any cline-no">&nbsp;</span>
1149
+ <span class="cline-any cline-neutral">&nbsp;</span>
1150
+ <span class="cline-any cline-no">&nbsp;</span>
1151
+ <span class="cline-any cline-no">&nbsp;</span>
1152
+ <span class="cline-any cline-no">&nbsp;</span>
1153
+ <span class="cline-any cline-no">&nbsp;</span>
1154
+ <span class="cline-any cline-no">&nbsp;</span>
1155
+ <span class="cline-any cline-no">&nbsp;</span>
1156
+ <span class="cline-any cline-no">&nbsp;</span>
1157
+ <span class="cline-any cline-neutral">&nbsp;</span>
1158
+ <span class="cline-any cline-neutral">&nbsp;</span>
1159
+ <span class="cline-any cline-no">&nbsp;</span>
1160
+ <span class="cline-any cline-no">&nbsp;</span>
1161
+ <span class="cline-any cline-no">&nbsp;</span>
1162
+ <span class="cline-any cline-no">&nbsp;</span>
1163
+ <span class="cline-any cline-neutral">&nbsp;</span>
1164
+ <span class="cline-any cline-no">&nbsp;</span>
1165
+ <span class="cline-any cline-no">&nbsp;</span>
1166
+ <span class="cline-any cline-no">&nbsp;</span>
1167
+ <span class="cline-any cline-no">&nbsp;</span>
1168
+ <span class="cline-any cline-no">&nbsp;</span>
1169
+ <span class="cline-any cline-no">&nbsp;</span>
1170
+ <span class="cline-any cline-no">&nbsp;</span>
1171
+ <span class="cline-any cline-neutral">&nbsp;</span>
1172
+ <span class="cline-any cline-neutral">&nbsp;</span>
1173
+ <span class="cline-any cline-no">&nbsp;</span>
1174
+ <span class="cline-any cline-no">&nbsp;</span>
1175
+ <span class="cline-any cline-no">&nbsp;</span>
1176
+ <span class="cline-any cline-no">&nbsp;</span>
1177
+ <span class="cline-any cline-no">&nbsp;</span>
1178
+ <span class="cline-any cline-no">&nbsp;</span>
1179
+ <span class="cline-any cline-no">&nbsp;</span>
1180
+ <span class="cline-any cline-no">&nbsp;</span>
1181
+ <span class="cline-any cline-no">&nbsp;</span>
1182
+ <span class="cline-any cline-no">&nbsp;</span>
1183
+ <span class="cline-any cline-no">&nbsp;</span>
1184
+ <span class="cline-any cline-no">&nbsp;</span>
1185
+ <span class="cline-any cline-no">&nbsp;</span>
1186
+ <span class="cline-any cline-no">&nbsp;</span>
1187
+ <span class="cline-any cline-no">&nbsp;</span>
1188
+ <span class="cline-any cline-no">&nbsp;</span>
1189
+ <span class="cline-any cline-no">&nbsp;</span>
1190
+ <span class="cline-any cline-no">&nbsp;</span>
1191
+ <span class="cline-any cline-no">&nbsp;</span>
1192
+ <span class="cline-any cline-no">&nbsp;</span>
1193
+ <span class="cline-any cline-no">&nbsp;</span>
1194
+ <span class="cline-any cline-no">&nbsp;</span>
1195
+ <span class="cline-any cline-no">&nbsp;</span>
1196
+ <span class="cline-any cline-no">&nbsp;</span>
1197
+ <span class="cline-any cline-no">&nbsp;</span>
1198
+ <span class="cline-any cline-no">&nbsp;</span>
1199
+ <span class="cline-any cline-no">&nbsp;</span>
1200
+ <span class="cline-any cline-no">&nbsp;</span>
1201
+ <span class="cline-any cline-no">&nbsp;</span>
1202
+ <span class="cline-any cline-no">&nbsp;</span>
1203
+ <span class="cline-any cline-no">&nbsp;</span>
1204
+ <span class="cline-any cline-no">&nbsp;</span>
1205
+ <span class="cline-any cline-no">&nbsp;</span>
1206
+ <span class="cline-any cline-no">&nbsp;</span>
1207
+ <span class="cline-any cline-no">&nbsp;</span>
1208
+ <span class="cline-any cline-no">&nbsp;</span>
1209
+ <span class="cline-any cline-no">&nbsp;</span>
1210
+ <span class="cline-any cline-no">&nbsp;</span>
1211
+ <span class="cline-any cline-no">&nbsp;</span>
1212
+ <span class="cline-any cline-no">&nbsp;</span>
1213
+ <span class="cline-any cline-no">&nbsp;</span>
1214
+ <span class="cline-any cline-no">&nbsp;</span>
1215
+ <span class="cline-any cline-no">&nbsp;</span>
1216
+ <span class="cline-any cline-no">&nbsp;</span>
1217
+ <span class="cline-any cline-no">&nbsp;</span>
1218
+ <span class="cline-any cline-no">&nbsp;</span>
1219
+ <span class="cline-any cline-no">&nbsp;</span>
1220
+ <span class="cline-any cline-no">&nbsp;</span>
1221
+ <span class="cline-any cline-no">&nbsp;</span>
1222
+ <span class="cline-any cline-no">&nbsp;</span>
1223
+ <span class="cline-any cline-neutral">&nbsp;</span>
1224
+ <span class="cline-any cline-no">&nbsp;</span>
1225
+ <span class="cline-any cline-no">&nbsp;</span>
1226
+ <span class="cline-any cline-neutral">&nbsp;</span>
1227
+ <span class="cline-any cline-neutral">&nbsp;</span>
1228
+ <span class="cline-any cline-no">&nbsp;</span>
1229
+ <span class="cline-any cline-no">&nbsp;</span>
1230
+ <span class="cline-any cline-no">&nbsp;</span>
1231
+ <span class="cline-any cline-neutral">&nbsp;</span>
1232
+ <span class="cline-any cline-neutral">&nbsp;</span>
1233
+ <span class="cline-any cline-no">&nbsp;</span>
1234
+ <span class="cline-any cline-no">&nbsp;</span>
1235
+ <span class="cline-any cline-no">&nbsp;</span>
1236
+ <span class="cline-any cline-no">&nbsp;</span>
1237
+ <span class="cline-any cline-no">&nbsp;</span>
1238
+ <span class="cline-any cline-no">&nbsp;</span>
1239
+ <span class="cline-any cline-no">&nbsp;</span>
1240
+ <span class="cline-any cline-no">&nbsp;</span>
1241
+ <span class="cline-any cline-no">&nbsp;</span>
1242
+ <span class="cline-any cline-no">&nbsp;</span>
1243
+ <span class="cline-any cline-no">&nbsp;</span>
1244
+ <span class="cline-any cline-neutral">&nbsp;</span>
1245
+ <span class="cline-any cline-no">&nbsp;</span>
1246
+ <span class="cline-any cline-neutral">&nbsp;</span>
1247
+ <span class="cline-any cline-no">&nbsp;</span>
1248
+ <span class="cline-any cline-yes">1x</span>
1249
+ <span class="cline-any cline-neutral">&nbsp;</span>
1250
+ <span class="cline-any cline-yes">1x</span>
1251
+ <span class="cline-any cline-yes">1x</span>
1252
+ <span class="cline-any cline-yes">1x</span>
1253
+ <span class="cline-any cline-no">&nbsp;</span>
1254
+ <span class="cline-any cline-no">&nbsp;</span>
1255
+ <span class="cline-any cline-neutral">&nbsp;</span>
1256
+ <span class="cline-any cline-neutral">&nbsp;</span>
1257
+ <span class="cline-any cline-no">&nbsp;</span>
1258
+ <span class="cline-any cline-no">&nbsp;</span>
1259
+ <span class="cline-any cline-no">&nbsp;</span>
1260
+ <span class="cline-any cline-no">&nbsp;</span>
1261
+ <span class="cline-any cline-no">&nbsp;</span>
1262
+ <span class="cline-any cline-no">&nbsp;</span>
1263
+ <span class="cline-any cline-no">&nbsp;</span>
1264
+ <span class="cline-any cline-no">&nbsp;</span>
1265
+ <span class="cline-any cline-no">&nbsp;</span>
1266
+ <span class="cline-any cline-no">&nbsp;</span>
1267
+ <span class="cline-any cline-no">&nbsp;</span>
1268
+ <span class="cline-any cline-no">&nbsp;</span>
1269
+ <span class="cline-any cline-no">&nbsp;</span>
1270
+ <span class="cline-any cline-no">&nbsp;</span>
1271
+ <span class="cline-any cline-no">&nbsp;</span>
1272
+ <span class="cline-any cline-no">&nbsp;</span>
1273
+ <span class="cline-any cline-no">&nbsp;</span>
1274
+ <span class="cline-any cline-no">&nbsp;</span>
1275
+ <span class="cline-any cline-no">&nbsp;</span>
1276
+ <span class="cline-any cline-no">&nbsp;</span>
1277
+ <span class="cline-any cline-no">&nbsp;</span>
1278
+ <span class="cline-any cline-no">&nbsp;</span>
1279
+ <span class="cline-any cline-no">&nbsp;</span>
1280
+ <span class="cline-any cline-no">&nbsp;</span>
1281
+ <span class="cline-any cline-no">&nbsp;</span>
1282
+ <span class="cline-any cline-no">&nbsp;</span>
1283
+ <span class="cline-any cline-no">&nbsp;</span>
1284
+ <span class="cline-any cline-no">&nbsp;</span>
1285
+ <span class="cline-any cline-no">&nbsp;</span>
1286
+ <span class="cline-any cline-no">&nbsp;</span>
1287
+ <span class="cline-any cline-no">&nbsp;</span>
1288
+ <span class="cline-any cline-no">&nbsp;</span>
1289
+ <span class="cline-any cline-no">&nbsp;</span>
1290
+ <span class="cline-any cline-no">&nbsp;</span>
1291
+ <span class="cline-any cline-no">&nbsp;</span>
1292
+ <span class="cline-any cline-no">&nbsp;</span>
1293
+ <span class="cline-any cline-no">&nbsp;</span>
1294
+ <span class="cline-any cline-no">&nbsp;</span>
1295
+ <span class="cline-any cline-no">&nbsp;</span>
1296
+ <span class="cline-any cline-no">&nbsp;</span>
1297
+ <span class="cline-any cline-no">&nbsp;</span>
1298
+ <span class="cline-any cline-no">&nbsp;</span>
1299
+ <span class="cline-any cline-no">&nbsp;</span>
1300
+ <span class="cline-any cline-no">&nbsp;</span>
1301
+ <span class="cline-any cline-no">&nbsp;</span>
1302
+ <span class="cline-any cline-no">&nbsp;</span>
1303
+ <span class="cline-any cline-no">&nbsp;</span>
1304
+ <span class="cline-any cline-no">&nbsp;</span>
1305
+ <span class="cline-any cline-no">&nbsp;</span>
1306
+ <span class="cline-any cline-no">&nbsp;</span>
1307
+ <span class="cline-any cline-no">&nbsp;</span>
1308
+ <span class="cline-any cline-no">&nbsp;</span>
1309
+ <span class="cline-any cline-no">&nbsp;</span>
1310
+ <span class="cline-any cline-neutral">&nbsp;</span>
1311
+ <span class="cline-any cline-neutral">&nbsp;</span>
1312
+ <span class="cline-any cline-no">&nbsp;</span>
1313
+ <span class="cline-any cline-no">&nbsp;</span>
1314
+ <span class="cline-any cline-no">&nbsp;</span>
1315
+ <span class="cline-any cline-no">&nbsp;</span>
1316
+ <span class="cline-any cline-no">&nbsp;</span>
1317
+ <span class="cline-any cline-no">&nbsp;</span>
1318
+ <span class="cline-any cline-no">&nbsp;</span>
1319
+ <span class="cline-any cline-no">&nbsp;</span>
1320
+ <span class="cline-any cline-no">&nbsp;</span>
1321
+ <span class="cline-any cline-no">&nbsp;</span>
1322
+ <span class="cline-any cline-no">&nbsp;</span>
1323
+ <span class="cline-any cline-no">&nbsp;</span>
1324
+ <span class="cline-any cline-no">&nbsp;</span>
1325
+ <span class="cline-any cline-no">&nbsp;</span>
1326
+ <span class="cline-any cline-no">&nbsp;</span>
1327
+ <span class="cline-any cline-no">&nbsp;</span>
1328
+ <span class="cline-any cline-no">&nbsp;</span>
1329
+ <span class="cline-any cline-no">&nbsp;</span>
1330
+ <span class="cline-any cline-no">&nbsp;</span>
1331
+ <span class="cline-any cline-no">&nbsp;</span>
1332
+ <span class="cline-any cline-neutral">&nbsp;</span>
1333
+ <span class="cline-any cline-no">&nbsp;</span>
1334
+ <span class="cline-any cline-neutral">&nbsp;</span>
1335
+ <span class="cline-any cline-no">&nbsp;</span>
1336
+ <span class="cline-any cline-no">&nbsp;</span>
1337
+ <span class="cline-any cline-no">&nbsp;</span>
1338
+ <span class="cline-any cline-no">&nbsp;</span>
1339
+ <span class="cline-any cline-no">&nbsp;</span>
1340
+ <span class="cline-any cline-no">&nbsp;</span>
1341
+ <span class="cline-any cline-no">&nbsp;</span>
1342
+ <span class="cline-any cline-neutral">&nbsp;</span>
1343
+ <span class="cline-any cline-neutral">&nbsp;</span>
1344
+ <span class="cline-any cline-no">&nbsp;</span>
1345
+ <span class="cline-any cline-no">&nbsp;</span>
1346
+ <span class="cline-any cline-no">&nbsp;</span>
1347
+ <span class="cline-any cline-no">&nbsp;</span>
1348
+ <span class="cline-any cline-no">&nbsp;</span>
1349
+ <span class="cline-any cline-no">&nbsp;</span>
1350
+ <span class="cline-any cline-no">&nbsp;</span>
1351
+ <span class="cline-any cline-no">&nbsp;</span>
1352
+ <span class="cline-any cline-no">&nbsp;</span>
1353
+ <span class="cline-any cline-no">&nbsp;</span>
1354
+ <span class="cline-any cline-no">&nbsp;</span>
1355
+ <span class="cline-any cline-no">&nbsp;</span>
1356
+ <span class="cline-any cline-no">&nbsp;</span>
1357
+ <span class="cline-any cline-no">&nbsp;</span>
1358
+ <span class="cline-any cline-no">&nbsp;</span>
1359
+ <span class="cline-any cline-no">&nbsp;</span>
1360
+ <span class="cline-any cline-no">&nbsp;</span>
1361
+ <span class="cline-any cline-no">&nbsp;</span>
1362
+ <span class="cline-any cline-no">&nbsp;</span>
1363
+ <span class="cline-any cline-no">&nbsp;</span>
1364
+ <span class="cline-any cline-no">&nbsp;</span>
1365
+ <span class="cline-any cline-no">&nbsp;</span>
1366
+ <span class="cline-any cline-no">&nbsp;</span>
1367
+ <span class="cline-any cline-no">&nbsp;</span>
1368
+ <span class="cline-any cline-no">&nbsp;</span>
1369
+ <span class="cline-any cline-no">&nbsp;</span>
1370
+ <span class="cline-any cline-no">&nbsp;</span>
1371
+ <span class="cline-any cline-no">&nbsp;</span>
1372
+ <span class="cline-any cline-no">&nbsp;</span>
1373
+ <span class="cline-any cline-no">&nbsp;</span>
1374
+ <span class="cline-any cline-no">&nbsp;</span>
1375
+ <span class="cline-any cline-no">&nbsp;</span>
1376
+ <span class="cline-any cline-no">&nbsp;</span>
1377
+ <span class="cline-any cline-no">&nbsp;</span>
1378
+ <span class="cline-any cline-no">&nbsp;</span>
1379
+ <span class="cline-any cline-no">&nbsp;</span>
1380
+ <span class="cline-any cline-no">&nbsp;</span>
1381
+ <span class="cline-any cline-no">&nbsp;</span>
1382
+ <span class="cline-any cline-no">&nbsp;</span>
1383
+ <span class="cline-any cline-no">&nbsp;</span>
1384
+ <span class="cline-any cline-no">&nbsp;</span>
1385
+ <span class="cline-any cline-no">&nbsp;</span>
1386
+ <span class="cline-any cline-no">&nbsp;</span>
1387
+ <span class="cline-any cline-no">&nbsp;</span>
1388
+ <span class="cline-any cline-no">&nbsp;</span>
1389
+ <span class="cline-any cline-no">&nbsp;</span>
1390
+ <span class="cline-any cline-no">&nbsp;</span>
1391
+ <span class="cline-any cline-no">&nbsp;</span>
1392
+ <span class="cline-any cline-neutral">&nbsp;</span>
1393
+ <span class="cline-any cline-no">&nbsp;</span>
1394
+ <span class="cline-any cline-no">&nbsp;</span>
1395
+ <span class="cline-any cline-no">&nbsp;</span>
1396
+ <span class="cline-any cline-no">&nbsp;</span>
1397
+ <span class="cline-any cline-no">&nbsp;</span>
1398
+ <span class="cline-any cline-no">&nbsp;</span>
1399
+ <span class="cline-any cline-neutral">&nbsp;</span>
1400
+ <span class="cline-any cline-no">&nbsp;</span>
1401
+ <span class="cline-any cline-yes">1x</span>
1402
+ <span class="cline-any cline-neutral">&nbsp;</span>
1403
+ <span class="cline-any cline-yes">1x</span>
1404
+ <span class="cline-any cline-yes">1x</span>
1405
+ <span class="cline-any cline-yes">1x</span>
1406
+ <span class="cline-any cline-no">&nbsp;</span>
1407
+ <span class="cline-any cline-no">&nbsp;</span>
1408
+ <span class="cline-any cline-neutral">&nbsp;</span>
1409
+ <span class="cline-any cline-neutral">&nbsp;</span>
1410
+ <span class="cline-any cline-no">&nbsp;</span>
1411
+ <span class="cline-any cline-no">&nbsp;</span>
1412
+ <span class="cline-any cline-no">&nbsp;</span>
1413
+ <span class="cline-any cline-no">&nbsp;</span>
1414
+ <span class="cline-any cline-no">&nbsp;</span>
1415
+ <span class="cline-any cline-no">&nbsp;</span>
1416
+ <span class="cline-any cline-no">&nbsp;</span>
1417
+ <span class="cline-any cline-no">&nbsp;</span>
1418
+ <span class="cline-any cline-no">&nbsp;</span>
1419
+ <span class="cline-any cline-no">&nbsp;</span>
1420
+ <span class="cline-any cline-no">&nbsp;</span>
1421
+ <span class="cline-any cline-no">&nbsp;</span>
1422
+ <span class="cline-any cline-no">&nbsp;</span>
1423
+ <span class="cline-any cline-no">&nbsp;</span>
1424
+ <span class="cline-any cline-no">&nbsp;</span>
1425
+ <span class="cline-any cline-no">&nbsp;</span>
1426
+ <span class="cline-any cline-no">&nbsp;</span>
1427
+ <span class="cline-any cline-no">&nbsp;</span>
1428
+ <span class="cline-any cline-no">&nbsp;</span>
1429
+ <span class="cline-any cline-no">&nbsp;</span>
1430
+ <span class="cline-any cline-no">&nbsp;</span>
1431
+ <span class="cline-any cline-neutral">&nbsp;</span>
1432
+ <span class="cline-any cline-no">&nbsp;</span>
1433
+ <span class="cline-any cline-no">&nbsp;</span>
1434
+ <span class="cline-any cline-no">&nbsp;</span>
1435
+ <span class="cline-any cline-no">&nbsp;</span>
1436
+ <span class="cline-any cline-no">&nbsp;</span>
1437
+ <span class="cline-any cline-no">&nbsp;</span>
1438
+ <span class="cline-any cline-neutral">&nbsp;</span>
1439
+ <span class="cline-any cline-no">&nbsp;</span>
1440
+ <span class="cline-any cline-no">&nbsp;</span>
1441
+ <span class="cline-any cline-no">&nbsp;</span>
1442
+ <span class="cline-any cline-no">&nbsp;</span>
1443
+ <span class="cline-any cline-no">&nbsp;</span>
1444
+ <span class="cline-any cline-no">&nbsp;</span>
1445
+ <span class="cline-any cline-no">&nbsp;</span>
1446
+ <span class="cline-any cline-no">&nbsp;</span>
1447
+ <span class="cline-any cline-no">&nbsp;</span>
1448
+ <span class="cline-any cline-no">&nbsp;</span>
1449
+ <span class="cline-any cline-no">&nbsp;</span>
1450
+ <span class="cline-any cline-no">&nbsp;</span>
1451
+ <span class="cline-any cline-no">&nbsp;</span>
1452
+ <span class="cline-any cline-no">&nbsp;</span>
1453
+ <span class="cline-any cline-no">&nbsp;</span>
1454
+ <span class="cline-any cline-no">&nbsp;</span>
1455
+ <span class="cline-any cline-no">&nbsp;</span>
1456
+ <span class="cline-any cline-no">&nbsp;</span>
1457
+ <span class="cline-any cline-no">&nbsp;</span>
1458
+ <span class="cline-any cline-no">&nbsp;</span>
1459
+ <span class="cline-any cline-no">&nbsp;</span>
1460
+ <span class="cline-any cline-no">&nbsp;</span>
1461
+ <span class="cline-any cline-no">&nbsp;</span>
1462
+ <span class="cline-any cline-no">&nbsp;</span>
1463
+ <span class="cline-any cline-no">&nbsp;</span>
1464
+ <span class="cline-any cline-no">&nbsp;</span>
1465
+ <span class="cline-any cline-no">&nbsp;</span>
1466
+ <span class="cline-any cline-no">&nbsp;</span>
1467
+ <span class="cline-any cline-no">&nbsp;</span>
1468
+ <span class="cline-any cline-no">&nbsp;</span>
1469
+ <span class="cline-any cline-no">&nbsp;</span>
1470
+ <span class="cline-any cline-no">&nbsp;</span>
1471
+ <span class="cline-any cline-no">&nbsp;</span>
1472
+ <span class="cline-any cline-no">&nbsp;</span>
1473
+ <span class="cline-any cline-no">&nbsp;</span>
1474
+ <span class="cline-any cline-no">&nbsp;</span>
1475
+ <span class="cline-any cline-no">&nbsp;</span>
1476
+ <span class="cline-any cline-no">&nbsp;</span>
1477
+ <span class="cline-any cline-no">&nbsp;</span>
1478
+ <span class="cline-any cline-no">&nbsp;</span>
1479
+ <span class="cline-any cline-no">&nbsp;</span>
1480
+ <span class="cline-any cline-no">&nbsp;</span>
1481
+ <span class="cline-any cline-no">&nbsp;</span>
1482
+ <span class="cline-any cline-no">&nbsp;</span>
1483
+ <span class="cline-any cline-no">&nbsp;</span>
1484
+ <span class="cline-any cline-no">&nbsp;</span>
1485
+ <span class="cline-any cline-no">&nbsp;</span>
1486
+ <span class="cline-any cline-no">&nbsp;</span>
1487
+ <span class="cline-any cline-no">&nbsp;</span>
1488
+ <span class="cline-any cline-neutral">&nbsp;</span>
1489
+ <span class="cline-any cline-no">&nbsp;</span>
1490
+ <span class="cline-any cline-no">&nbsp;</span>
1491
+ <span class="cline-any cline-no">&nbsp;</span>
1492
+ <span class="cline-any cline-no">&nbsp;</span>
1493
+ <span class="cline-any cline-no">&nbsp;</span>
1494
+ <span class="cline-any cline-no">&nbsp;</span>
1495
+ <span class="cline-any cline-no">&nbsp;</span>
1496
+ <span class="cline-any cline-no">&nbsp;</span>
1497
+ <span class="cline-any cline-no">&nbsp;</span>
1498
+ <span class="cline-any cline-no">&nbsp;</span>
1499
+ <span class="cline-any cline-no">&nbsp;</span>
1500
+ <span class="cline-any cline-yes">1x</span>
1501
+ <span class="cline-any cline-neutral">&nbsp;</span>
1502
+ <span class="cline-any cline-yes">1x</span>
1503
+ <span class="cline-any cline-yes">1x</span>
1504
+ <span class="cline-any cline-yes">1x</span>
1505
+ <span class="cline-any cline-yes">1x</span>
1506
+ <span class="cline-any cline-yes">1x</span>
1507
+ <span class="cline-any cline-yes">1x</span>
1508
+ <span class="cline-any cline-yes">1x</span>
1509
+ <span class="cline-any cline-yes">1x</span>
1510
+ <span class="cline-any cline-yes">1x</span>
1511
+ <span class="cline-any cline-no">&nbsp;</span>
1512
+ <span class="cline-any cline-no">&nbsp;</span>
1513
+ <span class="cline-any cline-neutral">&nbsp;</span>
1514
+ <span class="cline-any cline-neutral">&nbsp;</span>
1515
+ <span class="cline-any cline-no">&nbsp;</span>
1516
+ <span class="cline-any cline-no">&nbsp;</span>
1517
+ <span class="cline-any cline-no">&nbsp;</span>
1518
+ <span class="cline-any cline-no">&nbsp;</span>
1519
+ <span class="cline-any cline-no">&nbsp;</span>
1520
+ <span class="cline-any cline-no">&nbsp;</span>
1521
+ <span class="cline-any cline-no">&nbsp;</span>
1522
+ <span class="cline-any cline-no">&nbsp;</span>
1523
+ <span class="cline-any cline-no">&nbsp;</span>
1524
+ <span class="cline-any cline-no">&nbsp;</span>
1525
+ <span class="cline-any cline-no">&nbsp;</span>
1526
+ <span class="cline-any cline-no">&nbsp;</span>
1527
+ <span class="cline-any cline-no">&nbsp;</span>
1528
+ <span class="cline-any cline-no">&nbsp;</span>
1529
+ <span class="cline-any cline-no">&nbsp;</span>
1530
+ <span class="cline-any cline-no">&nbsp;</span>
1531
+ <span class="cline-any cline-no">&nbsp;</span>
1532
+ <span class="cline-any cline-no">&nbsp;</span>
1533
+ <span class="cline-any cline-no">&nbsp;</span>
1534
+ <span class="cline-any cline-neutral">&nbsp;</span>
1535
+ <span class="cline-any cline-no">&nbsp;</span>
1536
+ <span class="cline-any cline-no">&nbsp;</span>
1537
+ <span class="cline-any cline-no">&nbsp;</span>
1538
+ <span class="cline-any cline-no">&nbsp;</span>
1539
+ <span class="cline-any cline-no">&nbsp;</span>
1540
+ <span class="cline-any cline-no">&nbsp;</span>
1541
+ <span class="cline-any cline-neutral">&nbsp;</span>
1542
+ <span class="cline-any cline-neutral">&nbsp;</span>
1543
+ <span class="cline-any cline-no">&nbsp;</span>
1544
+ <span class="cline-any cline-no">&nbsp;</span>
1545
+ <span class="cline-any cline-no">&nbsp;</span>
1546
+ <span class="cline-any cline-no">&nbsp;</span>
1547
+ <span class="cline-any cline-no">&nbsp;</span>
1548
+ <span class="cline-any cline-no">&nbsp;</span>
1549
+ <span class="cline-any cline-no">&nbsp;</span>
1550
+ <span class="cline-any cline-neutral">&nbsp;</span>
1551
+ <span class="cline-any cline-no">&nbsp;</span>
1552
+ <span class="cline-any cline-no">&nbsp;</span>
1553
+ <span class="cline-any cline-no">&nbsp;</span>
1554
+ <span class="cline-any cline-no">&nbsp;</span>
1555
+ <span class="cline-any cline-no">&nbsp;</span>
1556
+ <span class="cline-any cline-no">&nbsp;</span>
1557
+ <span class="cline-any cline-no">&nbsp;</span>
1558
+ <span class="cline-any cline-neutral">&nbsp;</span>
1559
+ <span class="cline-any cline-neutral">&nbsp;</span>
1560
+ <span class="cline-any cline-no">&nbsp;</span>
1561
+ <span class="cline-any cline-no">&nbsp;</span>
1562
+ <span class="cline-any cline-no">&nbsp;</span>
1563
+ <span class="cline-any cline-no">&nbsp;</span>
1564
+ <span class="cline-any cline-no">&nbsp;</span>
1565
+ <span class="cline-any cline-no">&nbsp;</span>
1566
+ <span class="cline-any cline-no">&nbsp;</span>
1567
+ <span class="cline-any cline-no">&nbsp;</span>
1568
+ <span class="cline-any cline-no">&nbsp;</span>
1569
+ <span class="cline-any cline-no">&nbsp;</span>
1570
+ <span class="cline-any cline-no">&nbsp;</span>
1571
+ <span class="cline-any cline-no">&nbsp;</span>
1572
+ <span class="cline-any cline-no">&nbsp;</span>
1573
+ <span class="cline-any cline-no">&nbsp;</span>
1574
+ <span class="cline-any cline-no">&nbsp;</span>
1575
+ <span class="cline-any cline-no">&nbsp;</span>
1576
+ <span class="cline-any cline-no">&nbsp;</span>
1577
+ <span class="cline-any cline-no">&nbsp;</span>
1578
+ <span class="cline-any cline-no">&nbsp;</span>
1579
+ <span class="cline-any cline-no">&nbsp;</span>
1580
+ <span class="cline-any cline-no">&nbsp;</span>
1581
+ <span class="cline-any cline-no">&nbsp;</span>
1582
+ <span class="cline-any cline-neutral">&nbsp;</span>
1583
+ <span class="cline-any cline-neutral">&nbsp;</span>
1584
+ <span class="cline-any cline-no">&nbsp;</span>
1585
+ <span class="cline-any cline-no">&nbsp;</span>
1586
+ <span class="cline-any cline-no">&nbsp;</span>
1587
+ <span class="cline-any cline-no">&nbsp;</span>
1588
+ <span class="cline-any cline-no">&nbsp;</span>
1589
+ <span class="cline-any cline-no">&nbsp;</span>
1590
+ <span class="cline-any cline-no">&nbsp;</span>
1591
+ <span class="cline-any cline-no">&nbsp;</span>
1592
+ <span class="cline-any cline-neutral">&nbsp;</span>
1593
+ <span class="cline-any cline-neutral">&nbsp;</span>
1594
+ <span class="cline-any cline-no">&nbsp;</span>
1595
+ <span class="cline-any cline-no">&nbsp;</span>
1596
+ <span class="cline-any cline-no">&nbsp;</span>
1597
+ <span class="cline-any cline-no">&nbsp;</span>
1598
+ <span class="cline-any cline-neutral">&nbsp;</span>
1599
+ <span class="cline-any cline-no">&nbsp;</span>
1600
+ <span class="cline-any cline-no">&nbsp;</span>
1601
+ <span class="cline-any cline-neutral">&nbsp;</span>
1602
+ <span class="cline-any cline-neutral">&nbsp;</span>
1603
+ <span class="cline-any cline-no">&nbsp;</span>
1604
+ <span class="cline-any cline-no">&nbsp;</span>
1605
+ <span class="cline-any cline-no">&nbsp;</span>
1606
+ <span class="cline-any cline-no">&nbsp;</span>
1607
+ <span class="cline-any cline-no">&nbsp;</span>
1608
+ <span class="cline-any cline-no">&nbsp;</span>
1609
+ <span class="cline-any cline-no">&nbsp;</span>
1610
+ <span class="cline-any cline-no">&nbsp;</span>
1611
+ <span class="cline-any cline-no">&nbsp;</span>
1612
+ <span class="cline-any cline-no">&nbsp;</span>
1613
+ <span class="cline-any cline-no">&nbsp;</span>
1614
+ <span class="cline-any cline-no">&nbsp;</span>
1615
+ <span class="cline-any cline-neutral">&nbsp;</span>
1616
+ <span class="cline-any cline-no">&nbsp;</span>
1617
+ <span class="cline-any cline-neutral">&nbsp;</span>
1618
+ <span class="cline-any cline-neutral">&nbsp;</span>
1619
+ <span class="cline-any cline-no">&nbsp;</span>
1620
+ <span class="cline-any cline-neutral">&nbsp;</span>
1621
+ <span class="cline-any cline-no">&nbsp;</span>
1622
+ <span class="cline-any cline-no">&nbsp;</span>
1623
+ <span class="cline-any cline-no">&nbsp;</span>
1624
+ <span class="cline-any cline-no">&nbsp;</span>
1625
+ <span class="cline-any cline-neutral">&nbsp;</span>
1626
+ <span class="cline-any cline-no">&nbsp;</span>
1627
+ <span class="cline-any cline-no">&nbsp;</span>
1628
+ <span class="cline-any cline-no">&nbsp;</span>
1629
+ <span class="cline-any cline-no">&nbsp;</span>
1630
+ <span class="cline-any cline-no">&nbsp;</span>
1631
+ <span class="cline-any cline-no">&nbsp;</span>
1632
+ <span class="cline-any cline-no">&nbsp;</span>
1633
+ <span class="cline-any cline-no">&nbsp;</span>
1634
+ <span class="cline-any cline-no">&nbsp;</span>
1635
+ <span class="cline-any cline-yes">1x</span>
1636
+ <span class="cline-any cline-neutral">&nbsp;</span>
1637
+ <span class="cline-any cline-yes">1x</span>
1638
+ <span class="cline-any cline-yes">1x</span>
1639
+ <span class="cline-any cline-yes">1x</span>
1640
+ <span class="cline-any cline-no">&nbsp;</span>
1641
+ <span class="cline-any cline-no">&nbsp;</span>
1642
+ <span class="cline-any cline-neutral">&nbsp;</span>
1643
+ <span class="cline-any cline-neutral">&nbsp;</span>
1644
+ <span class="cline-any cline-no">&nbsp;</span>
1645
+ <span class="cline-any cline-no">&nbsp;</span>
1646
+ <span class="cline-any cline-no">&nbsp;</span>
1647
+ <span class="cline-any cline-no">&nbsp;</span>
1648
+ <span class="cline-any cline-no">&nbsp;</span>
1649
+ <span class="cline-any cline-no">&nbsp;</span>
1650
+ <span class="cline-any cline-neutral">&nbsp;</span>
1651
+ <span class="cline-any cline-no">&nbsp;</span>
1652
+ <span class="cline-any cline-no">&nbsp;</span>
1653
+ <span class="cline-any cline-no">&nbsp;</span>
1654
+ <span class="cline-any cline-no">&nbsp;</span>
1655
+ <span class="cline-any cline-no">&nbsp;</span>
1656
+ <span class="cline-any cline-no">&nbsp;</span>
1657
+ <span class="cline-any cline-neutral">&nbsp;</span>
1658
+ <span class="cline-any cline-neutral">&nbsp;</span>
1659
+ <span class="cline-any cline-no">&nbsp;</span>
1660
+ <span class="cline-any cline-neutral">&nbsp;</span>
1661
+ <span class="cline-any cline-no">&nbsp;</span>
1662
+ <span class="cline-any cline-no">&nbsp;</span>
1663
+ <span class="cline-any cline-no">&nbsp;</span>
1664
+ <span class="cline-any cline-no">&nbsp;</span>
1665
+ <span class="cline-any cline-no">&nbsp;</span>
1666
+ <span class="cline-any cline-no">&nbsp;</span>
1667
+ <span class="cline-any cline-no">&nbsp;</span>
1668
+ <span class="cline-any cline-neutral">&nbsp;</span>
1669
+ <span class="cline-any cline-neutral">&nbsp;</span>
1670
+ <span class="cline-any cline-no">&nbsp;</span>
1671
+ <span class="cline-any cline-no">&nbsp;</span>
1672
+ <span class="cline-any cline-no">&nbsp;</span>
1673
+ <span class="cline-any cline-no">&nbsp;</span>
1674
+ <span class="cline-any cline-no">&nbsp;</span>
1675
+ <span class="cline-any cline-neutral">&nbsp;</span>
1676
+ <span class="cline-any cline-neutral">&nbsp;</span>
1677
+ <span class="cline-any cline-no">&nbsp;</span>
1678
+ <span class="cline-any cline-no">&nbsp;</span>
1679
+ <span class="cline-any cline-no">&nbsp;</span>
1680
+ <span class="cline-any cline-no">&nbsp;</span>
1681
+ <span class="cline-any cline-no">&nbsp;</span>
1682
+ <span class="cline-any cline-neutral">&nbsp;</span>
1683
+ <span class="cline-any cline-neutral">&nbsp;</span>
1684
+ <span class="cline-any cline-no">&nbsp;</span>
1685
+ <span class="cline-any cline-no">&nbsp;</span>
1686
+ <span class="cline-any cline-no">&nbsp;</span>
1687
+ <span class="cline-any cline-neutral">&nbsp;</span>
1688
+ <span class="cline-any cline-neutral">&nbsp;</span>
1689
+ <span class="cline-any cline-no">&nbsp;</span>
1690
+ <span class="cline-any cline-no">&nbsp;</span>
1691
+ <span class="cline-any cline-no">&nbsp;</span>
1692
+ <span class="cline-any cline-no">&nbsp;</span>
1693
+ <span class="cline-any cline-neutral">&nbsp;</span>
1694
+ <span class="cline-any cline-neutral">&nbsp;</span>
1695
+ <span class="cline-any cline-no">&nbsp;</span>
1696
+ <span class="cline-any cline-no">&nbsp;</span>
1697
+ <span class="cline-any cline-no">&nbsp;</span>
1698
+ <span class="cline-any cline-no">&nbsp;</span>
1699
+ <span class="cline-any cline-no">&nbsp;</span>
1700
+ <span class="cline-any cline-no">&nbsp;</span>
1701
+ <span class="cline-any cline-no">&nbsp;</span>
1702
+ <span class="cline-any cline-neutral">&nbsp;</span>
1703
+ <span class="cline-any cline-no">&nbsp;</span>
1704
+ <span class="cline-any cline-neutral">&nbsp;</span>
1705
+ <span class="cline-any cline-no">&nbsp;</span>
1706
+ <span class="cline-any cline-yes">1x</span>
1707
+ <span class="cline-any cline-yes">1x</span>
1708
+ <span class="cline-any cline-neutral">&nbsp;</span>
1709
+ <span class="cline-any cline-neutral">&nbsp;</span>
1710
+ <span class="cline-any cline-neutral">&nbsp;</span>
1711
+ <span class="cline-any cline-neutral">&nbsp;</span>
1712
+ <span class="cline-any cline-neutral">&nbsp;</span>
1713
+ <span class="cline-any cline-no">&nbsp;</span>
1714
+ <span class="cline-any cline-no">&nbsp;</span>
1715
+ <span class="cline-any cline-no">&nbsp;</span>
1716
+ <span class="cline-any cline-no">&nbsp;</span>
1717
+ <span class="cline-any cline-no">&nbsp;</span>
1718
+ <span class="cline-any cline-no">&nbsp;</span>
1719
+ <span class="cline-any cline-no">&nbsp;</span>
1720
+ <span class="cline-any cline-neutral">&nbsp;</span>
1721
+ <span class="cline-any cline-no">&nbsp;</span>
1722
+ <span class="cline-any cline-neutral">&nbsp;</span>
1723
+ <span class="cline-any cline-neutral">&nbsp;</span>
1724
+ <span class="cline-any cline-neutral">&nbsp;</span>
1725
+ <span class="cline-any cline-neutral">&nbsp;</span>
1726
+ <span class="cline-any cline-neutral">&nbsp;</span>
1727
+ <span class="cline-any cline-neutral">&nbsp;</span>
1728
+ <span class="cline-any cline-neutral">&nbsp;</span>
1729
+ <span class="cline-any cline-neutral">&nbsp;</span>
1730
+ <span class="cline-any cline-neutral">&nbsp;</span>
1731
+ <span class="cline-any cline-neutral">&nbsp;</span>
1732
+ <span class="cline-any cline-no">&nbsp;</span>
1733
+ <span class="cline-any cline-no">&nbsp;</span>
1734
+ <span class="cline-any cline-no">&nbsp;</span>
1735
+ <span class="cline-any cline-no">&nbsp;</span>
1736
+ <span class="cline-any cline-no">&nbsp;</span>
1737
+ <span class="cline-any cline-no">&nbsp;</span>
1738
+ <span class="cline-any cline-no">&nbsp;</span>
1739
+ <span class="cline-any cline-no">&nbsp;</span>
1740
+ <span class="cline-any cline-no">&nbsp;</span>
1741
+ <span class="cline-any cline-no">&nbsp;</span>
1742
+ <span class="cline-any cline-no">&nbsp;</span>
1743
+ <span class="cline-any cline-no">&nbsp;</span>
1744
+ <span class="cline-any cline-neutral">&nbsp;</span>
1745
+ <span class="cline-any cline-no">&nbsp;</span>
1746
+ <span class="cline-any cline-neutral">&nbsp;</span>
1747
+ <span class="cline-any cline-no">&nbsp;</span>
1748
+ <span class="cline-any cline-no">&nbsp;</span>
1749
+ <span class="cline-any cline-no">&nbsp;</span>
1750
+ <span class="cline-any cline-neutral">&nbsp;</span>
1751
+ <span class="cline-any cline-neutral">&nbsp;</span>
1752
+ <span class="cline-any cline-no">&nbsp;</span>
1753
+ <span class="cline-any cline-no">&nbsp;</span>
1754
+ <span class="cline-any cline-no">&nbsp;</span>
1755
+ <span class="cline-any cline-neutral">&nbsp;</span>
1756
+ <span class="cline-any cline-no">&nbsp;</span>
1757
+ <span class="cline-any cline-neutral">&nbsp;</span>
1758
+ <span class="cline-any cline-no">&nbsp;</span>
1759
+ <span class="cline-any cline-no">&nbsp;</span>
1760
+ <span class="cline-any cline-neutral">&nbsp;</span>
1761
+ <span class="cline-any cline-neutral">&nbsp;</span>
1762
+ <span class="cline-any cline-no">&nbsp;</span>
1763
+ <span class="cline-any cline-no">&nbsp;</span>
1764
+ <span class="cline-any cline-neutral">&nbsp;</span>
1765
+ <span class="cline-any cline-no">&nbsp;</span>
1766
+ <span class="cline-any cline-no">&nbsp;</span>
1767
+ <span class="cline-any cline-no">&nbsp;</span>
1768
+ <span class="cline-any cline-neutral">&nbsp;</span>
1769
+ <span class="cline-any cline-no">&nbsp;</span>
1770
+ <span class="cline-any cline-neutral">&nbsp;</span>
1771
+ <span class="cline-any cline-no">&nbsp;</span>
1772
+ <span class="cline-any cline-no">&nbsp;</span>
1773
+ <span class="cline-any cline-no">&nbsp;</span>
1774
+ <span class="cline-any cline-no">&nbsp;</span>
1775
+ <span class="cline-any cline-no">&nbsp;</span>
1776
+ <span class="cline-any cline-neutral">&nbsp;</span>
1777
+ <span class="cline-any cline-neutral">&nbsp;</span>
1778
+ <span class="cline-any cline-neutral">&nbsp;</span>
1779
+ <span class="cline-any cline-neutral">&nbsp;</span>
1780
+ <span class="cline-any cline-neutral">&nbsp;</span>
1781
+ <span class="cline-any cline-no">&nbsp;</span>
1782
+ <span class="cline-any cline-no">&nbsp;</span>
1783
+ <span class="cline-any cline-no">&nbsp;</span>
1784
+ <span class="cline-any cline-no">&nbsp;</span>
1785
+ <span class="cline-any cline-no">&nbsp;</span>
1786
+ <span class="cline-any cline-no">&nbsp;</span>
1787
+ <span class="cline-any cline-neutral">&nbsp;</span>
1788
+ <span class="cline-any cline-no">&nbsp;</span>
1789
+ <span class="cline-any cline-no">&nbsp;</span>
1790
+ <span class="cline-any cline-no">&nbsp;</span>
1791
+ <span class="cline-any cline-no">&nbsp;</span>
1792
+ <span class="cline-any cline-no">&nbsp;</span>
1793
+ <span class="cline-any cline-no">&nbsp;</span>
1794
+ <span class="cline-any cline-no">&nbsp;</span>
1795
+ <span class="cline-any cline-no">&nbsp;</span>
1796
+ <span class="cline-any cline-no">&nbsp;</span>
1797
+ <span class="cline-any cline-no">&nbsp;</span>
1798
+ <span class="cline-any cline-no">&nbsp;</span>
1799
+ <span class="cline-any cline-neutral">&nbsp;</span>
1800
+ <span class="cline-any cline-no">&nbsp;</span>
1801
+ <span class="cline-any cline-no">&nbsp;</span>
1802
+ <span class="cline-any cline-no">&nbsp;</span>
1803
+ <span class="cline-any cline-neutral">&nbsp;</span>
1804
+ <span class="cline-any cline-neutral">&nbsp;</span>
1805
+ <span class="cline-any cline-no">&nbsp;</span>
1806
+ <span class="cline-any cline-no">&nbsp;</span>
1807
+ <span class="cline-any cline-no">&nbsp;</span>
1808
+ <span class="cline-any cline-no">&nbsp;</span>
1809
+ <span class="cline-any cline-no">&nbsp;</span>
1810
+ <span class="cline-any cline-no">&nbsp;</span>
1811
+ <span class="cline-any cline-no">&nbsp;</span>
1812
+ <span class="cline-any cline-no">&nbsp;</span>
1813
+ <span class="cline-any cline-no">&nbsp;</span>
1814
+ <span class="cline-any cline-no">&nbsp;</span>
1815
+ <span class="cline-any cline-no">&nbsp;</span>
1816
+ <span class="cline-any cline-no">&nbsp;</span>
1817
+ <span class="cline-any cline-no">&nbsp;</span>
1818
+ <span class="cline-any cline-no">&nbsp;</span>
1819
+ <span class="cline-any cline-no">&nbsp;</span>
1820
+ <span class="cline-any cline-no">&nbsp;</span>
1821
+ <span class="cline-any cline-no">&nbsp;</span>
1822
+ <span class="cline-any cline-no">&nbsp;</span>
1823
+ <span class="cline-any cline-no">&nbsp;</span>
1824
+ <span class="cline-any cline-no">&nbsp;</span>
1825
+ <span class="cline-any cline-no">&nbsp;</span>
1826
+ <span class="cline-any cline-no">&nbsp;</span>
1827
+ <span class="cline-any cline-neutral">&nbsp;</span>
1828
+ <span class="cline-any cline-neutral">&nbsp;</span>
1829
+ <span class="cline-any cline-neutral">&nbsp;</span>
1830
+ <span class="cline-any cline-no">&nbsp;</span>
1831
+ <span class="cline-any cline-neutral">&nbsp;</span>
1832
+ <span class="cline-any cline-neutral">&nbsp;</span>
1833
+ <span class="cline-any cline-neutral">&nbsp;</span>
1834
+ <span class="cline-any cline-neutral">&nbsp;</span>
1835
+ <span class="cline-any cline-neutral">&nbsp;</span>
1836
+ <span class="cline-any cline-neutral">&nbsp;</span>
1837
+ <span class="cline-any cline-neutral">&nbsp;</span>
1838
+ <span class="cline-any cline-neutral">&nbsp;</span>
1839
+ <span class="cline-any cline-neutral">&nbsp;</span>
1840
+ <span class="cline-any cline-neutral">&nbsp;</span>
1841
+ <span class="cline-any cline-neutral">&nbsp;</span>
1842
+ <span class="cline-any cline-neutral">&nbsp;</span>
1843
+ <span class="cline-any cline-neutral">&nbsp;</span>
1844
+ <span class="cline-any cline-neutral">&nbsp;</span>
1845
+ <span class="cline-any cline-neutral">&nbsp;</span>
1846
+ <span class="cline-any cline-neutral">&nbsp;</span>
1847
+ <span class="cline-any cline-neutral">&nbsp;</span>
1848
+ <span class="cline-any cline-neutral">&nbsp;</span>
1849
+ <span class="cline-any cline-neutral">&nbsp;</span>
1850
+ <span class="cline-any cline-neutral">&nbsp;</span>
1851
+ <span class="cline-any cline-neutral">&nbsp;</span>
1852
+ <span class="cline-any cline-neutral">&nbsp;</span>
1853
+ <span class="cline-any cline-neutral">&nbsp;</span>
1854
+ <span class="cline-any cline-neutral">&nbsp;</span>
1855
+ <span class="cline-any cline-neutral">&nbsp;</span>
1856
+ <span class="cline-any cline-neutral">&nbsp;</span>
1857
+ <span class="cline-any cline-neutral">&nbsp;</span>
1858
+ <span class="cline-any cline-neutral">&nbsp;</span>
1859
+ <span class="cline-any cline-neutral">&nbsp;</span>
1860
+ <span class="cline-any cline-neutral">&nbsp;</span>
1861
+ <span class="cline-any cline-neutral">&nbsp;</span>
1862
+ <span class="cline-any cline-neutral">&nbsp;</span>
1863
+ <span class="cline-any cline-neutral">&nbsp;</span>
1864
+ <span class="cline-any cline-no">&nbsp;</span>
1865
+ <span class="cline-any cline-no">&nbsp;</span>
1866
+ <span class="cline-any cline-no">&nbsp;</span>
1867
+ <span class="cline-any cline-neutral">&nbsp;</span>
1868
+ <span class="cline-any cline-neutral">&nbsp;</span>
1869
+ <span class="cline-any cline-no">&nbsp;</span>
1870
+ <span class="cline-any cline-no">&nbsp;</span>
1871
+ <span class="cline-any cline-no">&nbsp;</span>
1872
+ <span class="cline-any cline-no">&nbsp;</span>
1873
+ <span class="cline-any cline-neutral">&nbsp;</span>
1874
+ <span class="cline-any cline-no">&nbsp;</span>
1875
+ <span class="cline-any cline-no">&nbsp;</span>
1876
+ <span class="cline-any cline-no">&nbsp;</span>
1877
+ <span class="cline-any cline-no">&nbsp;</span>
1878
+ <span class="cline-any cline-no">&nbsp;</span>
1879
+ <span class="cline-any cline-neutral">&nbsp;</span>
1880
+ <span class="cline-any cline-neutral">&nbsp;</span>
1881
+ <span class="cline-any cline-no">&nbsp;</span>
1882
+ <span class="cline-any cline-no">&nbsp;</span>
1883
+ <span class="cline-any cline-no">&nbsp;</span>
1884
+ <span class="cline-any cline-no">&nbsp;</span>
1885
+ <span class="cline-any cline-no">&nbsp;</span>
1886
+ <span class="cline-any cline-neutral">&nbsp;</span>
1887
+ <span class="cline-any cline-neutral">&nbsp;</span>
1888
+ <span class="cline-any cline-no">&nbsp;</span>
1889
+ <span class="cline-any cline-no">&nbsp;</span>
1890
+ <span class="cline-any cline-no">&nbsp;</span>
1891
+ <span class="cline-any cline-no">&nbsp;</span>
1892
+ <span class="cline-any cline-no">&nbsp;</span>
1893
+ <span class="cline-any cline-no">&nbsp;</span>
1894
+ <span class="cline-any cline-neutral">&nbsp;</span>
1895
+ <span class="cline-any cline-no">&nbsp;</span>
1896
+ <span class="cline-any cline-no">&nbsp;</span>
1897
+ <span class="cline-any cline-no">&nbsp;</span>
1898
+ <span class="cline-any cline-no">&nbsp;</span>
1899
+ <span class="cline-any cline-no">&nbsp;</span>
1900
+ <span class="cline-any cline-no">&nbsp;</span>
1901
+ <span class="cline-any cline-no">&nbsp;</span>
1902
+ <span class="cline-any cline-no">&nbsp;</span>
1903
+ <span class="cline-any cline-no">&nbsp;</span>
1904
+ <span class="cline-any cline-no">&nbsp;</span>
1905
+ <span class="cline-any cline-no">&nbsp;</span>
1906
+ <span class="cline-any cline-no">&nbsp;</span>
1907
+ <span class="cline-any cline-no">&nbsp;</span>
1908
+ <span class="cline-any cline-no">&nbsp;</span>
1909
+ <span class="cline-any cline-no">&nbsp;</span>
1910
+ <span class="cline-any cline-no">&nbsp;</span>
1911
+ <span class="cline-any cline-no">&nbsp;</span>
1912
+ <span class="cline-any cline-no">&nbsp;</span>
1913
+ <span class="cline-any cline-no">&nbsp;</span>
1914
+ <span class="cline-any cline-no">&nbsp;</span>
1915
+ <span class="cline-any cline-no">&nbsp;</span>
1916
+ <span class="cline-any cline-no">&nbsp;</span>
1917
+ <span class="cline-any cline-no">&nbsp;</span>
1918
+ <span class="cline-any cline-no">&nbsp;</span>
1919
+ <span class="cline-any cline-no">&nbsp;</span>
1920
+ <span class="cline-any cline-no">&nbsp;</span>
1921
+ <span class="cline-any cline-no">&nbsp;</span>
1922
+ <span class="cline-any cline-no">&nbsp;</span>
1923
+ <span class="cline-any cline-no">&nbsp;</span>
1924
+ <span class="cline-any cline-no">&nbsp;</span>
1925
+ <span class="cline-any cline-no">&nbsp;</span>
1926
+ <span class="cline-any cline-no">&nbsp;</span>
1927
+ <span class="cline-any cline-no">&nbsp;</span>
1928
+ <span class="cline-any cline-no">&nbsp;</span>
1929
+ <span class="cline-any cline-no">&nbsp;</span>
1930
+ <span class="cline-any cline-no">&nbsp;</span>
1931
+ <span class="cline-any cline-no">&nbsp;</span>
1932
+ <span class="cline-any cline-no">&nbsp;</span>
1933
+ <span class="cline-any cline-no">&nbsp;</span>
1934
+ <span class="cline-any cline-no">&nbsp;</span>
1935
+ <span class="cline-any cline-no">&nbsp;</span>
1936
+ <span class="cline-any cline-no">&nbsp;</span>
1937
+ <span class="cline-any cline-no">&nbsp;</span>
1938
+ <span class="cline-any cline-no">&nbsp;</span>
1939
+ <span class="cline-any cline-no">&nbsp;</span>
1940
+ <span class="cline-any cline-no">&nbsp;</span>
1941
+ <span class="cline-any cline-no">&nbsp;</span>
1942
+ <span class="cline-any cline-no">&nbsp;</span>
1943
+ <span class="cline-any cline-no">&nbsp;</span>
1944
+ <span class="cline-any cline-no">&nbsp;</span>
1945
+ <span class="cline-any cline-no">&nbsp;</span>
1946
+ <span class="cline-any cline-no">&nbsp;</span>
1947
+ <span class="cline-any cline-no">&nbsp;</span>
1948
+ <span class="cline-any cline-no">&nbsp;</span>
1949
+ <span class="cline-any cline-neutral">&nbsp;</span>
1950
+ <span class="cline-any cline-no">&nbsp;</span>
1951
+ <span class="cline-any cline-neutral">&nbsp;</span>
1952
+ <span class="cline-any cline-no">&nbsp;</span>
1953
+ <span class="cline-any cline-no">&nbsp;</span>
1954
+ <span class="cline-any cline-no">&nbsp;</span>
1955
+ <span class="cline-any cline-neutral">&nbsp;</span>
1956
+ <span class="cline-any cline-neutral">&nbsp;</span>
1957
+ <span class="cline-any cline-no">&nbsp;</span>
1958
+ <span class="cline-any cline-no">&nbsp;</span>
1959
+ <span class="cline-any cline-neutral">&nbsp;</span>
1960
+ <span class="cline-any cline-neutral">&nbsp;</span>
1961
+ <span class="cline-any cline-no">&nbsp;</span>
1962
+ <span class="cline-any cline-neutral">&nbsp;</span>
1963
+ <span class="cline-any cline-no">&nbsp;</span>
1964
+ <span class="cline-any cline-neutral">&nbsp;</span>
1965
+ <span class="cline-any cline-neutral">&nbsp;</span>
1966
+ <span class="cline-any cline-no">&nbsp;</span>
1967
+ <span class="cline-any cline-no">&nbsp;</span>
1968
+ <span class="cline-any cline-no">&nbsp;</span>
1969
+ <span class="cline-any cline-no">&nbsp;</span>
1970
+ <span class="cline-any cline-no">&nbsp;</span>
1971
+ <span class="cline-any cline-no">&nbsp;</span>
1972
+ <span class="cline-any cline-neutral">&nbsp;</span>
1973
+ <span class="cline-any cline-neutral">&nbsp;</span>
1974
+ <span class="cline-any cline-no">&nbsp;</span>
1975
+ <span class="cline-any cline-no">&nbsp;</span>
1976
+ <span class="cline-any cline-no">&nbsp;</span>
1977
+ <span class="cline-any cline-neutral">&nbsp;</span>
1978
+ <span class="cline-any cline-no">&nbsp;</span>
1979
+ <span class="cline-any cline-no">&nbsp;</span>
1980
+ <span class="cline-any cline-no">&nbsp;</span>
1981
+ <span class="cline-any cline-no">&nbsp;</span>
1982
+ <span class="cline-any cline-neutral">&nbsp;</span>
1983
+ <span class="cline-any cline-no">&nbsp;</span>
1984
+ <span class="cline-any cline-no">&nbsp;</span>
1985
+ <span class="cline-any cline-neutral">&nbsp;</span>
1986
+ <span class="cline-any cline-no">&nbsp;</span>
1987
+ <span class="cline-any cline-neutral">&nbsp;</span>
1988
+ <span class="cline-any cline-neutral">&nbsp;</span>
1989
+ <span class="cline-any cline-no">&nbsp;</span>
1990
+ <span class="cline-any cline-no">&nbsp;</span>
1991
+ <span class="cline-any cline-no">&nbsp;</span>
1992
+ <span class="cline-any cline-no">&nbsp;</span>
1993
+ <span class="cline-any cline-no">&nbsp;</span>
1994
+ <span class="cline-any cline-no">&nbsp;</span>
1995
+ <span class="cline-any cline-neutral">&nbsp;</span>
1996
+ <span class="cline-any cline-no">&nbsp;</span>
1997
+ <span class="cline-any cline-neutral">&nbsp;</span>
1998
+ <span class="cline-any cline-no">&nbsp;</span>
1999
+ <span class="cline-any cline-no">&nbsp;</span>
2000
+ <span class="cline-any cline-no">&nbsp;</span>
2001
+ <span class="cline-any cline-no">&nbsp;</span>
2002
+ <span class="cline-any cline-no">&nbsp;</span>
2003
+ <span class="cline-any cline-no">&nbsp;</span>
2004
+ <span class="cline-any cline-no">&nbsp;</span>
2005
+ <span class="cline-any cline-no">&nbsp;</span>
2006
+ <span class="cline-any cline-no">&nbsp;</span>
2007
+ <span class="cline-any cline-no">&nbsp;</span>
2008
+ <span class="cline-any cline-no">&nbsp;</span>
2009
+ <span class="cline-any cline-no">&nbsp;</span>
2010
+ <span class="cline-any cline-no">&nbsp;</span>
2011
+ <span class="cline-any cline-no">&nbsp;</span>
2012
+ <span class="cline-any cline-no">&nbsp;</span>
2013
+ <span class="cline-any cline-no">&nbsp;</span>
2014
+ <span class="cline-any cline-no">&nbsp;</span>
2015
+ <span class="cline-any cline-no">&nbsp;</span>
2016
+ <span class="cline-any cline-no">&nbsp;</span>
2017
+ <span class="cline-any cline-no">&nbsp;</span>
2018
+ <span class="cline-any cline-no">&nbsp;</span>
2019
+ <span class="cline-any cline-no">&nbsp;</span>
2020
+ <span class="cline-any cline-no">&nbsp;</span>
2021
+ <span class="cline-any cline-no">&nbsp;</span>
2022
+ <span class="cline-any cline-no">&nbsp;</span>
2023
+ <span class="cline-any cline-no">&nbsp;</span>
2024
+ <span class="cline-any cline-no">&nbsp;</span>
2025
+ <span class="cline-any cline-no">&nbsp;</span>
2026
+ <span class="cline-any cline-neutral">&nbsp;</span>
2027
+ <span class="cline-any cline-neutral">&nbsp;</span>
2028
+ <span class="cline-any cline-no">&nbsp;</span>
2029
+ <span class="cline-any cline-no">&nbsp;</span>
2030
+ <span class="cline-any cline-no">&nbsp;</span>
2031
+ <span class="cline-any cline-no">&nbsp;</span>
2032
+ <span class="cline-any cline-no">&nbsp;</span>
2033
+ <span class="cline-any cline-no">&nbsp;</span>
2034
+ <span class="cline-any cline-no">&nbsp;</span>
2035
+ <span class="cline-any cline-no">&nbsp;</span>
2036
+ <span class="cline-any cline-neutral">&nbsp;</span>
2037
+ <span class="cline-any cline-no">&nbsp;</span>
2038
+ <span class="cline-any cline-no">&nbsp;</span>
2039
+ <span class="cline-any cline-no">&nbsp;</span>
2040
+ <span class="cline-any cline-no">&nbsp;</span>
2041
+ <span class="cline-any cline-neutral">&nbsp;</span>
2042
+ <span class="cline-any cline-no">&nbsp;</span>
2043
+ <span class="cline-any cline-neutral">&nbsp;</span>
2044
+ <span class="cline-any cline-no">&nbsp;</span>
2045
+ <span class="cline-any cline-no">&nbsp;</span>
2046
+ <span class="cline-any cline-no">&nbsp;</span>
2047
+ <span class="cline-any cline-no">&nbsp;</span>
2048
+ <span class="cline-any cline-no">&nbsp;</span>
2049
+ <span class="cline-any cline-no">&nbsp;</span>
2050
+ <span class="cline-any cline-no">&nbsp;</span>
2051
+ <span class="cline-any cline-no">&nbsp;</span>
2052
+ <span class="cline-any cline-no">&nbsp;</span>
2053
+ <span class="cline-any cline-no">&nbsp;</span>
2054
+ <span class="cline-any cline-no">&nbsp;</span>
2055
+ <span class="cline-any cline-no">&nbsp;</span>
2056
+ <span class="cline-any cline-no">&nbsp;</span>
2057
+ <span class="cline-any cline-neutral">&nbsp;</span>
2058
+ <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import { z } from 'zod';
2059
+ import { createTRPCRouter, protectedProcedure } from '../trpc.js';
2060
+ import { prisma } from '../lib/prisma.js';
2061
+ import { pusher } from '../lib/pusher.js';
2062
+ import { TRPCError } from '@trpc/server';
2063
+ import {
2064
+ inferenceClient,
2065
+ sendAIMessage,
2066
+ type LabChatContext
2067
+ } from '../utils/inference.js';
2068
+ import { logger } from '../utils/logger.js';
2069
+ import { isAIUser } from '../utils/aiUser.js';
2070
+ import { bucket } from '../lib/googleCloudStorage.js';
2071
+ import { createPdf } from "../lib/jsonConversion.js"
2072
+ import OpenAI from 'openai';
2073
+ import { v4 as uuidv4 } from "uuid";
2074
+ &nbsp;
2075
+ export const labChatRouter = createTRPCRouter({
2076
+ create: protectedProcedure
2077
+ .input(
2078
+ z.object({
2079
+ classId: z.string(),
2080
+ title: z.string().min(1).max(200),
2081
+ context: z.string(), // JSON string for LLM context
2082
+ })
2083
+ )
2084
+ .mutation(async ({ input, ctx }) =&gt; {
2085
+ <span class="cstat-no" title="statement not covered" > const userId = ctx.user!.id;</span>
2086
+ <span class="cstat-no" title="statement not covered" > const { classId, title, context } = input;</span>
2087
+ &nbsp;
2088
+ // Verify user is a teacher in the class
2089
+ <span class="cstat-no" title="statement not covered" > const classWithTeachers = await prisma.class.findFirst({</span>
2090
+ <span class="cstat-no" title="statement not covered" > where: {</span>
2091
+ <span class="cstat-no" title="statement not covered" > id: classId,</span>
2092
+ <span class="cstat-no" title="statement not covered" > teachers: {</span>
2093
+ <span class="cstat-no" title="statement not covered" > some: {</span>
2094
+ <span class="cstat-no" title="statement not covered" > id: userId,</span>
2095
+ <span class="cstat-no" title="statement not covered" > },</span>
2096
+ <span class="cstat-no" title="statement not covered" > },</span>
2097
+ <span class="cstat-no" title="statement not covered" > },</span>
2098
+ <span class="cstat-no" title="statement not covered" > include: {</span>
2099
+ <span class="cstat-no" title="statement not covered" > students: {</span>
2100
+ <span class="cstat-no" title="statement not covered" > select: {</span>
2101
+ <span class="cstat-no" title="statement not covered" > id: true,</span>
2102
+ <span class="cstat-no" title="statement not covered" > username: true,</span>
2103
+ <span class="cstat-no" title="statement not covered" > profile: {</span>
2104
+ <span class="cstat-no" title="statement not covered" > select: {</span>
2105
+ <span class="cstat-no" title="statement not covered" > displayName: true,</span>
2106
+ <span class="cstat-no" title="statement not covered" > profilePicture: true,</span>
2107
+ <span class="cstat-no" title="statement not covered" > },</span>
2108
+ <span class="cstat-no" title="statement not covered" > },</span>
2109
+ <span class="cstat-no" title="statement not covered" > },</span>
2110
+ <span class="cstat-no" title="statement not covered" > },</span>
2111
+ <span class="cstat-no" title="statement not covered" > teachers: {</span>
2112
+ <span class="cstat-no" title="statement not covered" > select: {</span>
2113
+ <span class="cstat-no" title="statement not covered" > id: true,</span>
2114
+ <span class="cstat-no" title="statement not covered" > username: true,</span>
2115
+ <span class="cstat-no" title="statement not covered" > profile: {</span>
2116
+ <span class="cstat-no" title="statement not covered" > select: {</span>
2117
+ <span class="cstat-no" title="statement not covered" > displayName: true,</span>
2118
+ <span class="cstat-no" title="statement not covered" > profilePicture: true,</span>
2119
+ <span class="cstat-no" title="statement not covered" > },</span>
2120
+ <span class="cstat-no" title="statement not covered" > },</span>
2121
+ <span class="cstat-no" title="statement not covered" > },</span>
2122
+ <span class="cstat-no" title="statement not covered" > },</span>
2123
+ <span class="cstat-no" title="statement not covered" > },</span>
2124
+ <span class="cstat-no" title="statement not covered" > });</span>
2125
+ &nbsp;
2126
+ <span class="cstat-no" title="statement not covered" > if (!classWithTeachers) {</span>
2127
+ <span class="cstat-no" title="statement not covered" > throw new TRPCError({</span>
2128
+ <span class="cstat-no" title="statement not covered" > code: 'FORBIDDEN',</span>
2129
+ <span class="cstat-no" title="statement not covered" > message: 'Not a teacher in this class',</span>
2130
+ <span class="cstat-no" title="statement not covered" > });</span>
2131
+ <span class="cstat-no" title="statement not covered" > }</span>
2132
+ &nbsp;
2133
+ // Validate context is valid JSON
2134
+ <span class="cstat-no" title="statement not covered" > try {</span>
2135
+ <span class="cstat-no" title="statement not covered" > JSON.parse(context);</span>
2136
+ <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
2137
+ <span class="cstat-no" title="statement not covered" > throw new TRPCError({</span>
2138
+ <span class="cstat-no" title="statement not covered" > code: 'BAD_REQUEST',</span>
2139
+ <span class="cstat-no" title="statement not covered" > message: 'Context must be valid JSON',</span>
2140
+ <span class="cstat-no" title="statement not covered" > });</span>
2141
+ <span class="cstat-no" title="statement not covered" > }</span>
2142
+ &nbsp;
2143
+ // Create lab chat with associated conversation
2144
+ <span class="cstat-no" title="statement not covered" > const result = await prisma.$transaction(async (tx) =&gt; {</span>
2145
+ // Create conversation for the lab chat
2146
+ <span class="cstat-no" title="statement not covered" > const conversation = await tx.conversation.create({</span>
2147
+ <span class="cstat-no" title="statement not covered" > data: {</span>
2148
+ <span class="cstat-no" title="statement not covered" > type: 'GROUP',</span>
2149
+ <span class="cstat-no" title="statement not covered" > name: `Lab: ${title}`,</span>
2150
+ <span class="cstat-no" title="statement not covered" > displayInChat: false, // Lab chats don't show in regular chat list</span>
2151
+ <span class="cstat-no" title="statement not covered" > },</span>
2152
+ <span class="cstat-no" title="statement not covered" > });</span>
2153
+ &nbsp;
2154
+ // Add only teachers to the conversation (this is for course material creation)
2155
+ <span class="cstat-no" title="statement not covered" > const teacherMembers = classWithTeachers.teachers.map(t =&gt; ({ </span>
2156
+ <span class="cstat-no" title="statement not covered" > userId: t.id, </span>
2157
+ <span class="cstat-no" title="statement not covered" > role: 'ADMIN' as const </span>
2158
+ <span class="cstat-no" title="statement not covered" > }));</span>
2159
+ &nbsp;
2160
+ <span class="cstat-no" title="statement not covered" > await tx.conversationMember.createMany({</span>
2161
+ <span class="cstat-no" title="statement not covered" > data: teacherMembers.map(member =&gt; ({</span>
2162
+ <span class="cstat-no" title="statement not covered" > userId: member.userId,</span>
2163
+ <span class="cstat-no" title="statement not covered" > conversationId: conversation.id,</span>
2164
+ <span class="cstat-no" title="statement not covered" > role: member.role,</span>
2165
+ <span class="cstat-no" title="statement not covered" > })),</span>
2166
+ <span class="cstat-no" title="statement not covered" > });</span>
2167
+ &nbsp;
2168
+ // Create the lab chat
2169
+ <span class="cstat-no" title="statement not covered" > const labChat = await tx.labChat.create({</span>
2170
+ <span class="cstat-no" title="statement not covered" > data: {</span>
2171
+ <span class="cstat-no" title="statement not covered" > title,</span>
2172
+ <span class="cstat-no" title="statement not covered" > context,</span>
2173
+ <span class="cstat-no" title="statement not covered" > classId,</span>
2174
+ <span class="cstat-no" title="statement not covered" > conversationId: conversation.id,</span>
2175
+ <span class="cstat-no" title="statement not covered" > createdById: userId,</span>
2176
+ <span class="cstat-no" title="statement not covered" > },</span>
2177
+ <span class="cstat-no" title="statement not covered" > include: {</span>
2178
+ <span class="cstat-no" title="statement not covered" > conversation: {</span>
2179
+ <span class="cstat-no" title="statement not covered" > include: {</span>
2180
+ <span class="cstat-no" title="statement not covered" > members: {</span>
2181
+ <span class="cstat-no" title="statement not covered" > include: {</span>
2182
+ <span class="cstat-no" title="statement not covered" > user: {</span>
2183
+ <span class="cstat-no" title="statement not covered" > select: {</span>
2184
+ <span class="cstat-no" title="statement not covered" > id: true,</span>
2185
+ <span class="cstat-no" title="statement not covered" > username: true,</span>
2186
+ <span class="cstat-no" title="statement not covered" > profile: {</span>
2187
+ <span class="cstat-no" title="statement not covered" > select: {</span>
2188
+ <span class="cstat-no" title="statement not covered" > displayName: true,</span>
2189
+ <span class="cstat-no" title="statement not covered" > profilePicture: true,</span>
2190
+ <span class="cstat-no" title="statement not covered" > },</span>
2191
+ <span class="cstat-no" title="statement not covered" > },</span>
2192
+ <span class="cstat-no" title="statement not covered" > },</span>
2193
+ <span class="cstat-no" title="statement not covered" > },</span>
2194
+ <span class="cstat-no" title="statement not covered" > },</span>
2195
+ <span class="cstat-no" title="statement not covered" > },</span>
2196
+ <span class="cstat-no" title="statement not covered" > },</span>
2197
+ <span class="cstat-no" title="statement not covered" > },</span>
2198
+ <span class="cstat-no" title="statement not covered" > createdBy: {</span>
2199
+ <span class="cstat-no" title="statement not covered" > select: {</span>
2200
+ <span class="cstat-no" title="statement not covered" > id: true,</span>
2201
+ <span class="cstat-no" title="statement not covered" > username: true,</span>
2202
+ <span class="cstat-no" title="statement not covered" > profile: {</span>
2203
+ <span class="cstat-no" title="statement not covered" > select: {</span>
2204
+ <span class="cstat-no" title="statement not covered" > displayName: true,</span>
2205
+ <span class="cstat-no" title="statement not covered" > },</span>
2206
+ <span class="cstat-no" title="statement not covered" > },</span>
2207
+ <span class="cstat-no" title="statement not covered" > },</span>
2208
+ <span class="cstat-no" title="statement not covered" > },</span>
2209
+ <span class="cstat-no" title="statement not covered" > class: {</span>
2210
+ <span class="cstat-no" title="statement not covered" > select: {</span>
2211
+ <span class="cstat-no" title="statement not covered" > id: true,</span>
2212
+ <span class="cstat-no" title="statement not covered" > name: true,</span>
2213
+ <span class="cstat-no" title="statement not covered" > subject: true,</span>
2214
+ <span class="cstat-no" title="statement not covered" > section: true,</span>
2215
+ <span class="cstat-no" title="statement not covered" > },</span>
2216
+ <span class="cstat-no" title="statement not covered" > },</span>
2217
+ <span class="cstat-no" title="statement not covered" > },</span>
2218
+ <span class="cstat-no" title="statement not covered" > });</span>
2219
+ &nbsp;
2220
+ <span class="cstat-no" title="statement not covered" > return labChat;</span>
2221
+ <span class="cstat-no" title="statement not covered" > });</span>
2222
+ &nbsp;
2223
+ // Generate AI introduction message in parallel (don't await - fire and forget)
2224
+ <span class="cstat-no" title="statement not covered" > generateAndSendLabIntroduction(result.id, result.conversationId, context, classWithTeachers.subject || 'Lab').catch(error =&gt; {</span>
2225
+ <span class="cstat-no" title="statement not covered" > logger.error('Failed to generate AI introduction:', { error, labChatId: result.id });</span>
2226
+ <span class="cstat-no" title="statement not covered" > });</span>
2227
+ &nbsp;
2228
+ // Broadcast lab chat creation to class members
2229
+ <span class="cstat-no" title="statement not covered" > try {</span>
2230
+ <span class="cstat-no" title="statement not covered" > await pusher.trigger(`class-${classId}`, 'lab-chat-created', {</span>
2231
+ <span class="cstat-no" title="statement not covered" > id: result.id,</span>
2232
+ <span class="cstat-no" title="statement not covered" > title: result.title,</span>
2233
+ <span class="cstat-no" title="statement not covered" > classId: result.classId,</span>
2234
+ <span class="cstat-no" title="statement not covered" > conversationId: result.conversationId,</span>
2235
+ <span class="cstat-no" title="statement not covered" > createdBy: result.createdBy,</span>
2236
+ <span class="cstat-no" title="statement not covered" > createdAt: result.createdAt,</span>
2237
+ <span class="cstat-no" title="statement not covered" > });</span>
2238
+ <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
2239
+ <span class="cstat-no" title="statement not covered" > console.error('Failed to broadcast lab chat creation:', error);</span>
2240
+ // Don't fail the request if Pusher fails
2241
+ <span class="cstat-no" title="statement not covered" > }</span>
2242
+ &nbsp;
2243
+ <span class="cstat-no" title="statement not covered" > return result;</span>
2244
+ }),
2245
+ &nbsp;
2246
+ get: protectedProcedure
2247
+ .input(z.object({ labChatId: z.string() }))
2248
+ .query(async ({ input, ctx }) =&gt; {
2249
+ <span class="cstat-no" title="statement not covered" > const userId = ctx.user!.id;</span>
2250
+ <span class="cstat-no" title="statement not covered" > const { labChatId } = input;</span>
2251
+ &nbsp;
2252
+ // First, try to find the lab chat if user is already a member
2253
+ <span class="cstat-no" title="statement not covered" > let labChat = await prisma.labChat.findFirst({</span>
2254
+ <span class="cstat-no" title="statement not covered" > where: {</span>
2255
+ <span class="cstat-no" title="statement not covered" > id: labChatId,</span>
2256
+ <span class="cstat-no" title="statement not covered" > conversation: {</span>
2257
+ <span class="cstat-no" title="statement not covered" > members: {</span>
2258
+ <span class="cstat-no" title="statement not covered" > some: {</span>
2259
+ <span class="cstat-no" title="statement not covered" > userId,</span>
2260
+ <span class="cstat-no" title="statement not covered" > },</span>
2261
+ <span class="cstat-no" title="statement not covered" > },</span>
2262
+ <span class="cstat-no" title="statement not covered" > },</span>
2263
+ <span class="cstat-no" title="statement not covered" > },</span>
2264
+ <span class="cstat-no" title="statement not covered" > include: {</span>
2265
+ <span class="cstat-no" title="statement not covered" > conversation: {</span>
2266
+ <span class="cstat-no" title="statement not covered" > include: {</span>
2267
+ <span class="cstat-no" title="statement not covered" > members: {</span>
2268
+ <span class="cstat-no" title="statement not covered" > include: {</span>
2269
+ <span class="cstat-no" title="statement not covered" > user: {</span>
2270
+ <span class="cstat-no" title="statement not covered" > select: {</span>
2271
+ <span class="cstat-no" title="statement not covered" > id: true,</span>
2272
+ <span class="cstat-no" title="statement not covered" > username: true,</span>
2273
+ <span class="cstat-no" title="statement not covered" > profile: {</span>
2274
+ <span class="cstat-no" title="statement not covered" > select: {</span>
2275
+ <span class="cstat-no" title="statement not covered" > displayName: true,</span>
2276
+ <span class="cstat-no" title="statement not covered" > profilePicture: true,</span>
2277
+ <span class="cstat-no" title="statement not covered" > },</span>
2278
+ <span class="cstat-no" title="statement not covered" > },</span>
2279
+ <span class="cstat-no" title="statement not covered" > },</span>
2280
+ <span class="cstat-no" title="statement not covered" > },</span>
2281
+ <span class="cstat-no" title="statement not covered" > },</span>
2282
+ <span class="cstat-no" title="statement not covered" > },</span>
2283
+ <span class="cstat-no" title="statement not covered" > },</span>
2284
+ <span class="cstat-no" title="statement not covered" > },</span>
2285
+ <span class="cstat-no" title="statement not covered" > createdBy: {</span>
2286
+ <span class="cstat-no" title="statement not covered" > select: {</span>
2287
+ <span class="cstat-no" title="statement not covered" > id: true,</span>
2288
+ <span class="cstat-no" title="statement not covered" > username: true,</span>
2289
+ <span class="cstat-no" title="statement not covered" > profile: {</span>
2290
+ <span class="cstat-no" title="statement not covered" > select: {</span>
2291
+ <span class="cstat-no" title="statement not covered" > displayName: true,</span>
2292
+ <span class="cstat-no" title="statement not covered" > },</span>
2293
+ <span class="cstat-no" title="statement not covered" > },</span>
2294
+ <span class="cstat-no" title="statement not covered" > },</span>
2295
+ <span class="cstat-no" title="statement not covered" > },</span>
2296
+ <span class="cstat-no" title="statement not covered" > class: {</span>
2297
+ <span class="cstat-no" title="statement not covered" > select: {</span>
2298
+ <span class="cstat-no" title="statement not covered" > id: true,</span>
2299
+ <span class="cstat-no" title="statement not covered" > name: true,</span>
2300
+ <span class="cstat-no" title="statement not covered" > subject: true,</span>
2301
+ <span class="cstat-no" title="statement not covered" > section: true,</span>
2302
+ <span class="cstat-no" title="statement not covered" > },</span>
2303
+ <span class="cstat-no" title="statement not covered" > },</span>
2304
+ <span class="cstat-no" title="statement not covered" > },</span>
2305
+ <span class="cstat-no" title="statement not covered" > });</span>
2306
+ &nbsp;
2307
+ // If not found, check if user is a teacher in the class
2308
+ <span class="cstat-no" title="statement not covered" > if (!labChat) {</span>
2309
+ <span class="cstat-no" title="statement not covered" > const labChatForTeacher = await prisma.labChat.findFirst({</span>
2310
+ <span class="cstat-no" title="statement not covered" > where: {</span>
2311
+ <span class="cstat-no" title="statement not covered" > id: labChatId,</span>
2312
+ <span class="cstat-no" title="statement not covered" > class: {</span>
2313
+ <span class="cstat-no" title="statement not covered" > teachers: {</span>
2314
+ <span class="cstat-no" title="statement not covered" > some: {</span>
2315
+ <span class="cstat-no" title="statement not covered" > id: userId,</span>
2316
+ <span class="cstat-no" title="statement not covered" > },</span>
2317
+ <span class="cstat-no" title="statement not covered" > },</span>
2318
+ <span class="cstat-no" title="statement not covered" > },</span>
2319
+ <span class="cstat-no" title="statement not covered" > },</span>
2320
+ <span class="cstat-no" title="statement not covered" > include: {</span>
2321
+ <span class="cstat-no" title="statement not covered" > conversation: {</span>
2322
+ <span class="cstat-no" title="statement not covered" > select: {</span>
2323
+ <span class="cstat-no" title="statement not covered" > id: true,</span>
2324
+ <span class="cstat-no" title="statement not covered" > },</span>
2325
+ <span class="cstat-no" title="statement not covered" > },</span>
2326
+ <span class="cstat-no" title="statement not covered" > },</span>
2327
+ <span class="cstat-no" title="statement not covered" > });</span>
2328
+ &nbsp;
2329
+ <span class="cstat-no" title="statement not covered" > if (labChatForTeacher) {</span>
2330
+ // Add teacher to conversation
2331
+ <span class="cstat-no" title="statement not covered" > await prisma.conversationMember.create({</span>
2332
+ <span class="cstat-no" title="statement not covered" > data: {</span>
2333
+ <span class="cstat-no" title="statement not covered" > userId,</span>
2334
+ <span class="cstat-no" title="statement not covered" > conversationId: labChatForTeacher.conversation.id,</span>
2335
+ <span class="cstat-no" title="statement not covered" > role: 'ADMIN',</span>
2336
+ <span class="cstat-no" title="statement not covered" > },</span>
2337
+ <span class="cstat-no" title="statement not covered" > });</span>
2338
+ &nbsp;
2339
+ // Now fetch the full lab chat with the user as a member
2340
+ <span class="cstat-no" title="statement not covered" > labChat = await prisma.labChat.findFirst({</span>
2341
+ <span class="cstat-no" title="statement not covered" > where: {</span>
2342
+ <span class="cstat-no" title="statement not covered" > id: labChatId,</span>
2343
+ <span class="cstat-no" title="statement not covered" > },</span>
2344
+ <span class="cstat-no" title="statement not covered" > include: {</span>
2345
+ <span class="cstat-no" title="statement not covered" > conversation: {</span>
2346
+ <span class="cstat-no" title="statement not covered" > include: {</span>
2347
+ <span class="cstat-no" title="statement not covered" > members: {</span>
2348
+ <span class="cstat-no" title="statement not covered" > include: {</span>
2349
+ <span class="cstat-no" title="statement not covered" > user: {</span>
2350
+ <span class="cstat-no" title="statement not covered" > select: {</span>
2351
+ <span class="cstat-no" title="statement not covered" > id: true,</span>
2352
+ <span class="cstat-no" title="statement not covered" > username: true,</span>
2353
+ <span class="cstat-no" title="statement not covered" > profile: {</span>
2354
+ <span class="cstat-no" title="statement not covered" > select: {</span>
2355
+ <span class="cstat-no" title="statement not covered" > displayName: true,</span>
2356
+ <span class="cstat-no" title="statement not covered" > profilePicture: true,</span>
2357
+ <span class="cstat-no" title="statement not covered" > },</span>
2358
+ <span class="cstat-no" title="statement not covered" > },</span>
2359
+ <span class="cstat-no" title="statement not covered" > },</span>
2360
+ <span class="cstat-no" title="statement not covered" > },</span>
2361
+ <span class="cstat-no" title="statement not covered" > },</span>
2362
+ <span class="cstat-no" title="statement not covered" > },</span>
2363
+ <span class="cstat-no" title="statement not covered" > },</span>
2364
+ <span class="cstat-no" title="statement not covered" > },</span>
2365
+ <span class="cstat-no" title="statement not covered" > createdBy: {</span>
2366
+ <span class="cstat-no" title="statement not covered" > select: {</span>
2367
+ <span class="cstat-no" title="statement not covered" > id: true,</span>
2368
+ <span class="cstat-no" title="statement not covered" > username: true,</span>
2369
+ <span class="cstat-no" title="statement not covered" > profile: {</span>
2370
+ <span class="cstat-no" title="statement not covered" > select: {</span>
2371
+ <span class="cstat-no" title="statement not covered" > displayName: true,</span>
2372
+ <span class="cstat-no" title="statement not covered" > },</span>
2373
+ <span class="cstat-no" title="statement not covered" > },</span>
2374
+ <span class="cstat-no" title="statement not covered" > },</span>
2375
+ <span class="cstat-no" title="statement not covered" > },</span>
2376
+ <span class="cstat-no" title="statement not covered" > class: {</span>
2377
+ <span class="cstat-no" title="statement not covered" > select: {</span>
2378
+ <span class="cstat-no" title="statement not covered" > id: true,</span>
2379
+ <span class="cstat-no" title="statement not covered" > name: true,</span>
2380
+ <span class="cstat-no" title="statement not covered" > subject: true,</span>
2381
+ <span class="cstat-no" title="statement not covered" > section: true,</span>
2382
+ <span class="cstat-no" title="statement not covered" > },</span>
2383
+ <span class="cstat-no" title="statement not covered" > },</span>
2384
+ <span class="cstat-no" title="statement not covered" > },</span>
2385
+ <span class="cstat-no" title="statement not covered" > });</span>
2386
+ <span class="cstat-no" title="statement not covered" > }</span>
2387
+ <span class="cstat-no" title="statement not covered" > }</span>
2388
+ &nbsp;
2389
+ <span class="cstat-no" title="statement not covered" > if (!labChat) {</span>
2390
+ <span class="cstat-no" title="statement not covered" > throw new TRPCError({</span>
2391
+ <span class="cstat-no" title="statement not covered" > code: 'NOT_FOUND',</span>
2392
+ <span class="cstat-no" title="statement not covered" > message: 'Lab chat not found or access denied',</span>
2393
+ <span class="cstat-no" title="statement not covered" > });</span>
2394
+ <span class="cstat-no" title="statement not covered" > }</span>
2395
+ &nbsp;
2396
+ <span class="cstat-no" title="statement not covered" > return labChat;</span>
2397
+ }),
2398
+ &nbsp;
2399
+ list: protectedProcedure
2400
+ .input(z.object({ classId: z.string() }))
2401
+ .query(async ({ input, ctx }) =&gt; {
2402
+ <span class="cstat-no" title="statement not covered" > const userId = ctx.user!.id;</span>
2403
+ <span class="cstat-no" title="statement not covered" > const { classId } = input;</span>
2404
+ &nbsp;
2405
+ // Verify user is a member of the class
2406
+ <span class="cstat-no" title="statement not covered" > const classMembership = await prisma.class.findFirst({</span>
2407
+ <span class="cstat-no" title="statement not covered" > where: {</span>
2408
+ <span class="cstat-no" title="statement not covered" > id: classId,</span>
2409
+ <span class="cstat-no" title="statement not covered" > OR: [</span>
2410
+ <span class="cstat-no" title="statement not covered" > {</span>
2411
+ <span class="cstat-no" title="statement not covered" > students: {</span>
2412
+ <span class="cstat-no" title="statement not covered" > some: {</span>
2413
+ <span class="cstat-no" title="statement not covered" > id: userId,</span>
2414
+ <span class="cstat-no" title="statement not covered" > },</span>
2415
+ <span class="cstat-no" title="statement not covered" > },</span>
2416
+ <span class="cstat-no" title="statement not covered" > },</span>
2417
+ <span class="cstat-no" title="statement not covered" > {</span>
2418
+ <span class="cstat-no" title="statement not covered" > teachers: {</span>
2419
+ <span class="cstat-no" title="statement not covered" > some: {</span>
2420
+ <span class="cstat-no" title="statement not covered" > id: userId,</span>
2421
+ <span class="cstat-no" title="statement not covered" > },</span>
2422
+ <span class="cstat-no" title="statement not covered" > },</span>
2423
+ <span class="cstat-no" title="statement not covered" > },</span>
2424
+ <span class="cstat-no" title="statement not covered" > ],</span>
2425
+ <span class="cstat-no" title="statement not covered" > },</span>
2426
+ <span class="cstat-no" title="statement not covered" > });</span>
2427
+ &nbsp;
2428
+ <span class="cstat-no" title="statement not covered" > if (!classMembership) {</span>
2429
+ <span class="cstat-no" title="statement not covered" > throw new TRPCError({</span>
2430
+ <span class="cstat-no" title="statement not covered" > code: 'FORBIDDEN',</span>
2431
+ <span class="cstat-no" title="statement not covered" > message: 'Not a member of this class',</span>
2432
+ <span class="cstat-no" title="statement not covered" > });</span>
2433
+ <span class="cstat-no" title="statement not covered" > }</span>
2434
+ &nbsp;
2435
+ <span class="cstat-no" title="statement not covered" > const labChats = await prisma.labChat.findMany({</span>
2436
+ <span class="cstat-no" title="statement not covered" > where: {</span>
2437
+ <span class="cstat-no" title="statement not covered" > classId,</span>
2438
+ <span class="cstat-no" title="statement not covered" > },</span>
2439
+ <span class="cstat-no" title="statement not covered" > include: {</span>
2440
+ <span class="cstat-no" title="statement not covered" > createdBy: {</span>
2441
+ <span class="cstat-no" title="statement not covered" > select: {</span>
2442
+ <span class="cstat-no" title="statement not covered" > id: true,</span>
2443
+ <span class="cstat-no" title="statement not covered" > username: true,</span>
2444
+ <span class="cstat-no" title="statement not covered" > profile: {</span>
2445
+ <span class="cstat-no" title="statement not covered" > select: {</span>
2446
+ <span class="cstat-no" title="statement not covered" > displayName: true,</span>
2447
+ <span class="cstat-no" title="statement not covered" > },</span>
2448
+ <span class="cstat-no" title="statement not covered" > },</span>
2449
+ <span class="cstat-no" title="statement not covered" > },</span>
2450
+ <span class="cstat-no" title="statement not covered" > },</span>
2451
+ <span class="cstat-no" title="statement not covered" > conversation: {</span>
2452
+ <span class="cstat-no" title="statement not covered" > include: {</span>
2453
+ <span class="cstat-no" title="statement not covered" > messages: {</span>
2454
+ <span class="cstat-no" title="statement not covered" > orderBy: {</span>
2455
+ <span class="cstat-no" title="statement not covered" > createdAt: 'desc',</span>
2456
+ <span class="cstat-no" title="statement not covered" > },</span>
2457
+ <span class="cstat-no" title="statement not covered" > take: 1,</span>
2458
+ <span class="cstat-no" title="statement not covered" > include: {</span>
2459
+ <span class="cstat-no" title="statement not covered" > sender: {</span>
2460
+ <span class="cstat-no" title="statement not covered" > select: {</span>
2461
+ <span class="cstat-no" title="statement not covered" > id: true,</span>
2462
+ <span class="cstat-no" title="statement not covered" > username: true,</span>
2463
+ <span class="cstat-no" title="statement not covered" > profile: {</span>
2464
+ <span class="cstat-no" title="statement not covered" > select: {</span>
2465
+ <span class="cstat-no" title="statement not covered" > displayName: true,</span>
2466
+ <span class="cstat-no" title="statement not covered" > },</span>
2467
+ <span class="cstat-no" title="statement not covered" > },</span>
2468
+ <span class="cstat-no" title="statement not covered" > },</span>
2469
+ <span class="cstat-no" title="statement not covered" > },</span>
2470
+ <span class="cstat-no" title="statement not covered" > },</span>
2471
+ <span class="cstat-no" title="statement not covered" > },</span>
2472
+ <span class="cstat-no" title="statement not covered" > _count: {</span>
2473
+ <span class="cstat-no" title="statement not covered" > select: {</span>
2474
+ <span class="cstat-no" title="statement not covered" > messages: true,</span>
2475
+ <span class="cstat-no" title="statement not covered" > },</span>
2476
+ <span class="cstat-no" title="statement not covered" > },</span>
2477
+ <span class="cstat-no" title="statement not covered" > },</span>
2478
+ <span class="cstat-no" title="statement not covered" > },</span>
2479
+ <span class="cstat-no" title="statement not covered" > },</span>
2480
+ <span class="cstat-no" title="statement not covered" > orderBy: {</span>
2481
+ <span class="cstat-no" title="statement not covered" > createdAt: 'desc',</span>
2482
+ <span class="cstat-no" title="statement not covered" > },</span>
2483
+ <span class="cstat-no" title="statement not covered" > });</span>
2484
+ &nbsp;
2485
+ <span class="cstat-no" title="statement not covered" > return labChats.map((labChat) =&gt; ({</span>
2486
+ <span class="cstat-no" title="statement not covered" > id: labChat.id,</span>
2487
+ <span class="cstat-no" title="statement not covered" > title: labChat.title,</span>
2488
+ <span class="cstat-no" title="statement not covered" > classId: labChat.classId,</span>
2489
+ <span class="cstat-no" title="statement not covered" > conversationId: labChat.conversationId,</span>
2490
+ <span class="cstat-no" title="statement not covered" > createdBy: labChat.createdBy,</span>
2491
+ <span class="cstat-no" title="statement not covered" > createdAt: labChat.createdAt,</span>
2492
+ <span class="cstat-no" title="statement not covered" > updatedAt: labChat.updatedAt,</span>
2493
+ <span class="cstat-no" title="statement not covered" > lastMessage: labChat.conversation.messages[0] || null,</span>
2494
+ <span class="cstat-no" title="statement not covered" > messageCount: labChat.conversation._count.messages,</span>
2495
+ <span class="cstat-no" title="statement not covered" > }));</span>
2496
+ }),
2497
+ &nbsp;
2498
+ postToLabChat: protectedProcedure
2499
+ .input(
2500
+ z.object({
2501
+ labChatId: z.string(),
2502
+ content: z.string().min(1).max(4000),
2503
+ mentionedUserIds: z.array(z.string()).optional(),
2504
+ })
2505
+ )
2506
+ .mutation(async ({ input, ctx }) =&gt; {
2507
+ <span class="cstat-no" title="statement not covered" > const userId = ctx.user!.id;</span>
2508
+ <span class="cstat-no" title="statement not covered" > const { labChatId, content, mentionedUserIds = [] } = input;</span>
2509
+ &nbsp;
2510
+ // Get lab chat and verify user is a member
2511
+ <span class="cstat-no" title="statement not covered" > const labChat = await prisma.labChat.findFirst({</span>
2512
+ <span class="cstat-no" title="statement not covered" > where: {</span>
2513
+ <span class="cstat-no" title="statement not covered" > id: labChatId,</span>
2514
+ <span class="cstat-no" title="statement not covered" > conversation: {</span>
2515
+ <span class="cstat-no" title="statement not covered" > members: {</span>
2516
+ <span class="cstat-no" title="statement not covered" > some: {</span>
2517
+ <span class="cstat-no" title="statement not covered" > userId,</span>
2518
+ <span class="cstat-no" title="statement not covered" > },</span>
2519
+ <span class="cstat-no" title="statement not covered" > },</span>
2520
+ <span class="cstat-no" title="statement not covered" > },</span>
2521
+ <span class="cstat-no" title="statement not covered" > },</span>
2522
+ <span class="cstat-no" title="statement not covered" > include: {</span>
2523
+ <span class="cstat-no" title="statement not covered" > conversation: {</span>
2524
+ <span class="cstat-no" title="statement not covered" > select: {</span>
2525
+ <span class="cstat-no" title="statement not covered" > id: true,</span>
2526
+ <span class="cstat-no" title="statement not covered" > },</span>
2527
+ <span class="cstat-no" title="statement not covered" > },</span>
2528
+ <span class="cstat-no" title="statement not covered" > },</span>
2529
+ <span class="cstat-no" title="statement not covered" > });</span>
2530
+ &nbsp;
2531
+ <span class="cstat-no" title="statement not covered" > if (!labChat) {</span>
2532
+ <span class="cstat-no" title="statement not covered" > throw new TRPCError({</span>
2533
+ <span class="cstat-no" title="statement not covered" > code: 'FORBIDDEN',</span>
2534
+ <span class="cstat-no" title="statement not covered" > message: 'Lab chat not found or access denied',</span>
2535
+ <span class="cstat-no" title="statement not covered" > });</span>
2536
+ <span class="cstat-no" title="statement not covered" > }</span>
2537
+ &nbsp;
2538
+ // Verify mentioned users are members of the conversation
2539
+ <span class="cstat-no" title="statement not covered" > if (mentionedUserIds.length &gt; 0) {</span>
2540
+ <span class="cstat-no" title="statement not covered" > const mentionedMemberships = await prisma.conversationMember.findMany({</span>
2541
+ <span class="cstat-no" title="statement not covered" > where: {</span>
2542
+ <span class="cstat-no" title="statement not covered" > conversationId: labChat.conversationId,</span>
2543
+ <span class="cstat-no" title="statement not covered" > userId: { in: mentionedUserIds },</span>
2544
+ <span class="cstat-no" title="statement not covered" > },</span>
2545
+ <span class="cstat-no" title="statement not covered" > });</span>
2546
+ &nbsp;
2547
+ <span class="cstat-no" title="statement not covered" > if (mentionedMemberships.length !== mentionedUserIds.length) {</span>
2548
+ <span class="cstat-no" title="statement not covered" > throw new TRPCError({</span>
2549
+ <span class="cstat-no" title="statement not covered" > code: 'BAD_REQUEST',</span>
2550
+ <span class="cstat-no" title="statement not covered" > message: 'Some mentioned users are not members of this lab chat',</span>
2551
+ <span class="cstat-no" title="statement not covered" > });</span>
2552
+ <span class="cstat-no" title="statement not covered" > }</span>
2553
+ <span class="cstat-no" title="statement not covered" > }</span>
2554
+ &nbsp;
2555
+ // Create message and mentions
2556
+ <span class="cstat-no" title="statement not covered" > const result = await prisma.$transaction(async (tx) =&gt; {</span>
2557
+ <span class="cstat-no" title="statement not covered" > const message = await tx.message.create({</span>
2558
+ <span class="cstat-no" title="statement not covered" > data: {</span>
2559
+ <span class="cstat-no" title="statement not covered" > content,</span>
2560
+ <span class="cstat-no" title="statement not covered" > senderId: userId,</span>
2561
+ <span class="cstat-no" title="statement not covered" > conversationId: labChat.conversationId,</span>
2562
+ <span class="cstat-no" title="statement not covered" > },</span>
2563
+ <span class="cstat-no" title="statement not covered" > include: {</span>
2564
+ <span class="cstat-no" title="statement not covered" > sender: {</span>
2565
+ <span class="cstat-no" title="statement not covered" > select: {</span>
2566
+ <span class="cstat-no" title="statement not covered" > id: true,</span>
2567
+ <span class="cstat-no" title="statement not covered" > username: true,</span>
2568
+ <span class="cstat-no" title="statement not covered" > profile: {</span>
2569
+ <span class="cstat-no" title="statement not covered" > select: {</span>
2570
+ <span class="cstat-no" title="statement not covered" > displayName: true,</span>
2571
+ <span class="cstat-no" title="statement not covered" > profilePicture: true,</span>
2572
+ <span class="cstat-no" title="statement not covered" > },</span>
2573
+ <span class="cstat-no" title="statement not covered" > },</span>
2574
+ <span class="cstat-no" title="statement not covered" > },</span>
2575
+ <span class="cstat-no" title="statement not covered" > },</span>
2576
+ <span class="cstat-no" title="statement not covered" > },</span>
2577
+ <span class="cstat-no" title="statement not covered" > });</span>
2578
+ &nbsp;
2579
+ // Create mentions
2580
+ <span class="cstat-no" title="statement not covered" > if (mentionedUserIds.length &gt; 0) {</span>
2581
+ <span class="cstat-no" title="statement not covered" > await tx.mention.createMany({</span>
2582
+ <span class="cstat-no" title="statement not covered" > data: mentionedUserIds.map((mentionedUserId) =&gt; ({</span>
2583
+ <span class="cstat-no" title="statement not covered" > messageId: message.id,</span>
2584
+ <span class="cstat-no" title="statement not covered" > userId: mentionedUserId,</span>
2585
+ <span class="cstat-no" title="statement not covered" > })),</span>
2586
+ <span class="cstat-no" title="statement not covered" > });</span>
2587
+ <span class="cstat-no" title="statement not covered" > }</span>
2588
+ &nbsp;
2589
+ // Update lab chat timestamp
2590
+ <span class="cstat-no" title="statement not covered" > await tx.labChat.update({</span>
2591
+ <span class="cstat-no" title="statement not covered" > where: { id: labChatId },</span>
2592
+ <span class="cstat-no" title="statement not covered" > data: { updatedAt: new Date() },</span>
2593
+ <span class="cstat-no" title="statement not covered" > });</span>
2594
+ &nbsp;
2595
+ <span class="cstat-no" title="statement not covered" > return message;</span>
2596
+ <span class="cstat-no" title="statement not covered" > });</span>
2597
+ &nbsp;
2598
+ // Broadcast to Pusher channel (same format as regular chat)
2599
+ <span class="cstat-no" title="statement not covered" > try {</span>
2600
+ <span class="cstat-no" title="statement not covered" > await pusher.trigger(`conversation-${labChat.conversationId}`, 'new-message', {</span>
2601
+ <span class="cstat-no" title="statement not covered" > id: result.id,</span>
2602
+ <span class="cstat-no" title="statement not covered" > content: result.content,</span>
2603
+ <span class="cstat-no" title="statement not covered" > senderId: result.senderId,</span>
2604
+ <span class="cstat-no" title="statement not covered" > conversationId: result.conversationId,</span>
2605
+ <span class="cstat-no" title="statement not covered" > createdAt: result.createdAt,</span>
2606
+ <span class="cstat-no" title="statement not covered" > sender: result.sender,</span>
2607
+ <span class="cstat-no" title="statement not covered" > mentionedUserIds,</span>
2608
+ <span class="cstat-no" title="statement not covered" > });</span>
2609
+ <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
2610
+ <span class="cstat-no" title="statement not covered" > console.error('Failed to broadcast lab chat message:', error);</span>
2611
+ // Don't fail the request if Pusher fails
2612
+ <span class="cstat-no" title="statement not covered" > }</span>
2613
+ &nbsp;
2614
+ // Generate AI response in parallel (don't await - fire and forget)
2615
+ <span class="cstat-no" title="statement not covered" > if (!isAIUser(userId)) {</span>
2616
+ // Run AI response generation in background
2617
+ <span class="cstat-no" title="statement not covered" > generateAndSendLabResponse(labChatId, content, labChat.conversationId).catch(error =&gt; {</span>
2618
+ <span class="cstat-no" title="statement not covered" > logger.error('Failed to generate AI response:', { error });</span>
2619
+ <span class="cstat-no" title="statement not covered" > });</span>
2620
+ <span class="cstat-no" title="statement not covered" > }</span>
2621
+ &nbsp;
2622
+ <span class="cstat-no" title="statement not covered" > return {</span>
2623
+ <span class="cstat-no" title="statement not covered" > id: result.id,</span>
2624
+ <span class="cstat-no" title="statement not covered" > content: result.content,</span>
2625
+ <span class="cstat-no" title="statement not covered" > senderId: result.senderId,</span>
2626
+ <span class="cstat-no" title="statement not covered" > conversationId: result.conversationId,</span>
2627
+ <span class="cstat-no" title="statement not covered" > createdAt: result.createdAt,</span>
2628
+ <span class="cstat-no" title="statement not covered" > sender: result.sender,</span>
2629
+ <span class="cstat-no" title="statement not covered" > mentionedUserIds,</span>
2630
+ <span class="cstat-no" title="statement not covered" > };</span>
2631
+ }),
2632
+ &nbsp;
2633
+ delete: protectedProcedure
2634
+ .input(z.object({ labChatId: z.string() }))
2635
+ .mutation(async ({ input, ctx }) =&gt; {
2636
+ <span class="cstat-no" title="statement not covered" > const userId = ctx.user!.id;</span>
2637
+ <span class="cstat-no" title="statement not covered" > const { labChatId } = input;</span>
2638
+ &nbsp;
2639
+ // Verify user is the creator of the lab chat
2640
+ <span class="cstat-no" title="statement not covered" > const labChat = await prisma.labChat.findFirst({</span>
2641
+ <span class="cstat-no" title="statement not covered" > where: {</span>
2642
+ <span class="cstat-no" title="statement not covered" > id: labChatId,</span>
2643
+ <span class="cstat-no" title="statement not covered" > createdById: userId,</span>
2644
+ <span class="cstat-no" title="statement not covered" > },</span>
2645
+ <span class="cstat-no" title="statement not covered" > });</span>
2646
+ &nbsp;
2647
+ <span class="cstat-no" title="statement not covered" > if (!labChat) {</span>
2648
+ <span class="cstat-no" title="statement not covered" > throw new TRPCError({</span>
2649
+ <span class="cstat-no" title="statement not covered" > code: 'FORBIDDEN',</span>
2650
+ <span class="cstat-no" title="statement not covered" > message: 'Lab chat not found or not the creator',</span>
2651
+ <span class="cstat-no" title="statement not covered" > });</span>
2652
+ <span class="cstat-no" title="statement not covered" > }</span>
2653
+ &nbsp;
2654
+ // Delete lab chat and associated conversation
2655
+ <span class="cstat-no" title="statement not covered" > await prisma.$transaction(async (tx) =&gt; {</span>
2656
+ // Delete mentions first
2657
+ <span class="cstat-no" title="statement not covered" > await tx.mention.deleteMany({</span>
2658
+ <span class="cstat-no" title="statement not covered" > where: {</span>
2659
+ <span class="cstat-no" title="statement not covered" > message: {</span>
2660
+ <span class="cstat-no" title="statement not covered" > conversationId: labChat.conversationId,</span>
2661
+ <span class="cstat-no" title="statement not covered" > },</span>
2662
+ <span class="cstat-no" title="statement not covered" > },</span>
2663
+ <span class="cstat-no" title="statement not covered" > });</span>
2664
+ &nbsp;
2665
+ // Delete messages
2666
+ <span class="cstat-no" title="statement not covered" > await tx.message.deleteMany({</span>
2667
+ <span class="cstat-no" title="statement not covered" > where: {</span>
2668
+ <span class="cstat-no" title="statement not covered" > conversationId: labChat.conversationId,</span>
2669
+ <span class="cstat-no" title="statement not covered" > },</span>
2670
+ <span class="cstat-no" title="statement not covered" > });</span>
2671
+ &nbsp;
2672
+ // Delete conversation members
2673
+ <span class="cstat-no" title="statement not covered" > await tx.conversationMember.deleteMany({</span>
2674
+ <span class="cstat-no" title="statement not covered" > where: {</span>
2675
+ <span class="cstat-no" title="statement not covered" > conversationId: labChat.conversationId,</span>
2676
+ <span class="cstat-no" title="statement not covered" > },</span>
2677
+ <span class="cstat-no" title="statement not covered" > });</span>
2678
+ &nbsp;
2679
+ // Delete lab chat
2680
+ <span class="cstat-no" title="statement not covered" > await tx.labChat.delete({</span>
2681
+ <span class="cstat-no" title="statement not covered" > where: { id: labChatId },</span>
2682
+ <span class="cstat-no" title="statement not covered" > });</span>
2683
+ &nbsp;
2684
+ // Delete conversation
2685
+ <span class="cstat-no" title="statement not covered" > await tx.conversation.delete({</span>
2686
+ <span class="cstat-no" title="statement not covered" > where: { id: labChat.conversationId },</span>
2687
+ <span class="cstat-no" title="statement not covered" > });</span>
2688
+ <span class="cstat-no" title="statement not covered" > });</span>
2689
+ &nbsp;
2690
+ // Broadcast lab chat deletion
2691
+ <span class="cstat-no" title="statement not covered" > try {</span>
2692
+ <span class="cstat-no" title="statement not covered" > await pusher.trigger(`class-${labChat.classId}`, 'lab-chat-deleted', {</span>
2693
+ <span class="cstat-no" title="statement not covered" > labChatId,</span>
2694
+ <span class="cstat-no" title="statement not covered" > classId: labChat.classId,</span>
2695
+ <span class="cstat-no" title="statement not covered" > });</span>
2696
+ <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
2697
+ <span class="cstat-no" title="statement not covered" > console.error('Failed to broadcast lab chat deletion:', error);</span>
2698
+ // Don't fail the request if Pusher fails
2699
+ <span class="cstat-no" title="statement not covered" > }</span>
2700
+ &nbsp;
2701
+ <span class="cstat-no" title="statement not covered" > return { success: true };</span>
2702
+ }),
2703
+ });
2704
+ &nbsp;
2705
+ /**
2706
+ * Generate and send AI introduction for lab chat
2707
+ * Uses the stored context directly from database
2708
+ */
2709
+ <span class="cstat-no" title="statement not covered" ><span class="fstat-no" title="function not covered" >async function generateAndSendLabIntroduction(</span></span>
2710
+ <span class="cstat-no" title="statement not covered" > labChatId: string,</span>
2711
+ <span class="cstat-no" title="statement not covered" > conversationId: string,</span>
2712
+ <span class="cstat-no" title="statement not covered" > contextString: string,</span>
2713
+ <span class="cstat-no" title="statement not covered" > subject: string</span>
2714
+ <span class="cstat-no" title="statement not covered" >): Promise&lt;void&gt; {</span>
2715
+ <span class="cstat-no" title="statement not covered" > try {</span>
2716
+ // Enhance the stored context with clarifying question instructions
2717
+ <span class="cstat-no" title="statement not covered" > const enhancedSystemPrompt = `${contextString}</span>
2718
+ &nbsp;
2719
+ IMPORTANT INSTRUCTIONS:
2720
+ - You are helping teachers create course materials
2721
+ - Use the context information provided above (subject, topic, difficulty, objectives, etc.) as your foundation
2722
+ - Only ask clarifying questions about details NOT already specified in the context
2723
+ - Focus your questions on format preferences, specific requirements, or missing details needed to create the content
2724
+ - Only output final course materials when you have sufficient details beyond what's in the context
2725
+ - Do not use markdown formatting in your responses - use plain text only
2726
+ - When creating content, make it clear and well-structured without markdown`;
2727
+ &nbsp;
2728
+ <span class="cstat-no" title="statement not covered" > const completion = await inferenceClient.chat.completions.create({</span>
2729
+ <span class="cstat-no" title="statement not covered" > model: 'command-a-03-2025',</span>
2730
+ <span class="cstat-no" title="statement not covered" > messages: [</span>
2731
+ <span class="cstat-no" title="statement not covered" > { role: 'system', content: enhancedSystemPrompt },</span>
2732
+ <span class="cstat-no" title="statement not covered" > { </span>
2733
+ <span class="cstat-no" title="statement not covered" > role: 'user', </span>
2734
+ <span class="cstat-no" title="statement not covered" > content: 'Please introduce yourself to the teaching team. Explain that you will help create course materials by first asking clarifying questions based on the context provided, and only output final content when you have enough information.' </span>
2735
+ <span class="cstat-no" title="statement not covered" > },</span>
2736
+ <span class="cstat-no" title="statement not covered" > ],</span>
2737
+ <span class="cstat-no" title="statement not covered" > max_tokens: 300,</span>
2738
+ <span class="cstat-no" title="statement not covered" > temperature: 0.8,</span>
2739
+ <span class="cstat-no" title="statement not covered" > });</span>
2740
+ &nbsp;
2741
+ <span class="cstat-no" title="statement not covered" > const response = completion.choices[0]?.message?.content;</span>
2742
+
2743
+ <span class="cstat-no" title="statement not covered" > if (!response) {</span>
2744
+ <span class="cstat-no" title="statement not covered" > throw new Error('No response generated from inference API');</span>
2745
+ <span class="cstat-no" title="statement not covered" > }</span>
2746
+ &nbsp;
2747
+ // Send AI introduction using centralized sender
2748
+ <span class="cstat-no" title="statement not covered" > await sendAIMessage(response, conversationId, {</span>
2749
+ <span class="cstat-no" title="statement not covered" > subject,</span>
2750
+ <span class="cstat-no" title="statement not covered" > });</span>
2751
+ &nbsp;
2752
+ <span class="cstat-no" title="statement not covered" > logger.info('AI Introduction sent', { labChatId, conversationId });</span>
2753
+ &nbsp;
2754
+ <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
2755
+ <span class="cstat-no" title="statement not covered" > logger.error('Failed to generate AI introduction:', { error, labChatId });</span>
2756
+
2757
+ // Send fallback introduction
2758
+ <span class="cstat-no" title="statement not covered" > try {</span>
2759
+ <span class="cstat-no" title="statement not covered" > const fallbackIntro = `Hello teaching team! I'm your AI assistant for course material development. I will help you create educational content by first asking clarifying questions based on the provided context, then outputting final materials when I have sufficient information. I won't use markdown formatting in my responses. What would you like to work on?`;</span>
2760
+
2761
+ <span class="cstat-no" title="statement not covered" > await sendAIMessage(fallbackIntro, conversationId, {</span>
2762
+ <span class="cstat-no" title="statement not covered" > subject,</span>
2763
+ <span class="cstat-no" title="statement not covered" > });</span>
2764
+ &nbsp;
2765
+ <span class="cstat-no" title="statement not covered" > logger.info('Fallback AI introduction sent', { labChatId });</span>
2766
+ &nbsp;
2767
+ <span class="cstat-no" title="statement not covered" > } catch (fallbackError) {</span>
2768
+ <span class="cstat-no" title="statement not covered" > logger.error('Failed to send fallback AI introduction:', { error: fallbackError, labChatId });</span>
2769
+ <span class="cstat-no" title="statement not covered" > }</span>
2770
+ <span class="cstat-no" title="statement not covered" > }</span>
2771
+ <span class="cstat-no" title="statement not covered" >}</span>
2772
+ &nbsp;
2773
+ /**
2774
+ * Generate and send AI response to teacher message
2775
+ * Uses the stored context directly from database
2776
+ */
2777
+ <span class="cstat-no" title="statement not covered" ><span class="fstat-no" title="function not covered" >async function generateAndSendLabResponse(</span></span>
2778
+ <span class="cstat-no" title="statement not covered" > labChatId: string,</span>
2779
+ <span class="cstat-no" title="statement not covered" > teacherMessage: string,</span>
2780
+ <span class="cstat-no" title="statement not covered" > conversationId: string</span>
2781
+ <span class="cstat-no" title="statement not covered" >): Promise&lt;void&gt; {</span>
2782
+ <span class="cstat-no" title="statement not covered" > try {</span>
2783
+ // Get lab context from database
2784
+ <span class="cstat-no" title="statement not covered" > const fullLabChat = await prisma.labChat.findUnique({</span>
2785
+ <span class="cstat-no" title="statement not covered" > where: { id: labChatId },</span>
2786
+ <span class="cstat-no" title="statement not covered" > include: {</span>
2787
+ <span class="cstat-no" title="statement not covered" > class: {</span>
2788
+ <span class="cstat-no" title="statement not covered" > select: {</span>
2789
+ <span class="cstat-no" title="statement not covered" > name: true,</span>
2790
+ <span class="cstat-no" title="statement not covered" > subject: true,</span>
2791
+ <span class="cstat-no" title="statement not covered" > },</span>
2792
+ <span class="cstat-no" title="statement not covered" > },</span>
2793
+ <span class="cstat-no" title="statement not covered" > },</span>
2794
+ <span class="cstat-no" title="statement not covered" > });</span>
2795
+ &nbsp;
2796
+ <span class="cstat-no" title="statement not covered" > if (!fullLabChat) {</span>
2797
+ <span class="cstat-no" title="statement not covered" > throw new Error('Lab chat not found');</span>
2798
+ <span class="cstat-no" title="statement not covered" > }</span>
2799
+ &nbsp;
2800
+ // Get recent conversation history
2801
+ <span class="cstat-no" title="statement not covered" > const recentMessages = await prisma.message.findMany({</span>
2802
+ <span class="cstat-no" title="statement not covered" > where: {</span>
2803
+ <span class="cstat-no" title="statement not covered" > conversationId,</span>
2804
+ <span class="cstat-no" title="statement not covered" > },</span>
2805
+ <span class="cstat-no" title="statement not covered" > include: {</span>
2806
+ <span class="cstat-no" title="statement not covered" > sender: {</span>
2807
+ <span class="cstat-no" title="statement not covered" > select: {</span>
2808
+ <span class="cstat-no" title="statement not covered" > id: true,</span>
2809
+ <span class="cstat-no" title="statement not covered" > username: true,</span>
2810
+ <span class="cstat-no" title="statement not covered" > profile: {</span>
2811
+ <span class="cstat-no" title="statement not covered" > select: {</span>
2812
+ <span class="cstat-no" title="statement not covered" > displayName: true,</span>
2813
+ <span class="cstat-no" title="statement not covered" > },</span>
2814
+ <span class="cstat-no" title="statement not covered" > },</span>
2815
+ <span class="cstat-no" title="statement not covered" > },</span>
2816
+ <span class="cstat-no" title="statement not covered" > },</span>
2817
+ <span class="cstat-no" title="statement not covered" > },</span>
2818
+ <span class="cstat-no" title="statement not covered" > orderBy: {</span>
2819
+ <span class="cstat-no" title="statement not covered" > createdAt: 'desc',</span>
2820
+ <span class="cstat-no" title="statement not covered" > },</span>
2821
+ <span class="cstat-no" title="statement not covered" > take: 10, // Last 10 messages for context</span>
2822
+ <span class="cstat-no" title="statement not covered" > });</span>
2823
+ &nbsp;
2824
+ // Build conversation history as proper message objects
2825
+ // Enhance the stored context with clarifying question instructions
2826
+ <span class="cstat-no" title="statement not covered" > const enhancedSystemPrompt = `${fullLabChat.context}</span>
2827
+ &nbsp;
2828
+ IMPORTANT INSTRUCTIONS:
2829
+ - Use the context information provided above (subject, topic, difficulty, objectives, etc.) as your foundation
2830
+ - Based on the teacher's input and existing context, only ask clarifying questions about details NOT already specified
2831
+ - Focus questions on format preferences, specific requirements, quantity, or missing implementation details
2832
+ - Only output final course materials when you have sufficient details beyond what's in the context
2833
+ - Do not use markdown formatting in your responses - use plain text only
2834
+ - When you do create content, make it clear and well-structured without markdown
2835
+ - If the request is vague, ask 1-2 specific clarifying questions about missing details only
2836
+ - You are primarily a chatbot - only provide files when it is necessary
2837
+ &nbsp;
2838
+ RESPONSE FORMAT:
2839
+ - Always respond with JSON in this format: { "text": string, "docs": null | array }
2840
+ - "text": Your conversational response (questions, explanations, etc.) - use plain text, no markdown
2841
+ - "docs": null for regular conversation, or array of PDF document objects when creating course materials
2842
+ &nbsp;
2843
+ WHEN CREATING COURSE MATERIALS (docs field):
2844
+ - docs: [ { "title": string, "blocks": [ { "format": &lt;int 0-12&gt;, "content": string | string[], "metadata"?: { fontSize?: number, lineHeight?: number, paragraphSpacing?: number, indentWidth?: number, paddingX?: number, paddingY?: number, font?: 0|1|2|3|4|5, color?: "#RGB"|"#RRGGBB", background?: "#RGB"|"#RRGGBB", align?: "left"|"center"|"right" } } ] } ]
2845
+ - Each document in the array should have a "title" (used for filename) and "blocks" (content)
2846
+ - You can create multiple documents when it makes sense (e.g., separate worksheets, answer keys, different topics)
2847
+ - Use descriptive titles like "Biology_Cell_Structure_Worksheet" or "Chemistry_Lab_Instructions"
2848
+ - Format enum (integers): 0=HEADER_1, 1=HEADER_2, 2=HEADER_3, 3=HEADER_4, 4=HEADER_5, 5=HEADER_6, 6=PARAGRAPH, 7=BULLET, 8=NUMBERED, 9=TABLE, 10=IMAGE, 11=CODE_BLOCK, 12=QUOTE
2849
+ - Fonts enum: 0=TIMES_ROMAN, 1=COURIER, 2=HELVETICA, 3=HELVETICA_BOLD, 4=HELVETICA_ITALIC, 5=HELVETICA_BOLD_ITALIC
2850
+ - Colors must be hex strings: "#RGB" or "#RRGGBB".
2851
+ - Headings (0-5): content is a single string; you may set metadata.align.
2852
+ - Paragraphs (6) and Quotes (12): content is a single string.
2853
+ - Bullets (7) and Numbered (8): content is an array of strings (one item per list entry). DO NOT include bullet symbols (*) or numbers (1. 2. 3.) in the content - the format will automatically add these.
2854
+ - Code blocks (11): prefer content as an array of lines; preserve indentation via leading tabs/spaces. If using a single string, include \n between lines.
2855
+ - Table (9) and Image (10) are not supported by the renderer now; do not emit them.
2856
+ - Use metadata sparingly; omit fields you don't need. For code blocks you may set metadata.paddingX, paddingY, background, and font (1 for Courier).
2857
+ - Wrap text naturally; do not insert manual line breaks except where semantically required (lists, code).
2858
+ - The JSON must be valid and ready for PDF rendering by the server.`;
2859
+ &nbsp;
2860
+ <span class="cstat-no" title="statement not covered" > const messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[] = [</span>
2861
+ <span class="cstat-no" title="statement not covered" > { role: 'system', content: enhancedSystemPrompt },</span>
2862
+ <span class="cstat-no" title="statement not covered" > ];</span>
2863
+ &nbsp;
2864
+ // Add recent conversation history
2865
+ <span class="cstat-no" title="statement not covered" > recentMessages.reverse().forEach(msg =&gt; {</span>
2866
+ <span class="cstat-no" title="statement not covered" > const role = isAIUser(msg.senderId) ? 'assistant' : 'user';</span>
2867
+ <span class="cstat-no" title="statement not covered" > const senderName = msg.sender?.profile?.displayName || msg.sender?.username || 'Teacher';</span>
2868
+ <span class="cstat-no" title="statement not covered" > const content = isAIUser(msg.senderId) ? msg.content : `${senderName}: ${msg.content}`;</span>
2869
+
2870
+ <span class="cstat-no" title="statement not covered" > messages.push({</span>
2871
+ <span class="cstat-no" title="statement not covered" > role: role as 'user' | 'assistant',</span>
2872
+ <span class="cstat-no" title="statement not covered" > content,</span>
2873
+ <span class="cstat-no" title="statement not covered" > });</span>
2874
+ <span class="cstat-no" title="statement not covered" > });</span>
2875
+ &nbsp;
2876
+ // Add the new teacher message
2877
+ <span class="cstat-no" title="statement not covered" > const senderName = 'Teacher'; // We could get this from the actual sender if needed</span>
2878
+ <span class="cstat-no" title="statement not covered" > messages.push({</span>
2879
+ <span class="cstat-no" title="statement not covered" > role: 'user',</span>
2880
+ <span class="cstat-no" title="statement not covered" > content: `${senderName}: ${teacherMessage}`,</span>
2881
+ <span class="cstat-no" title="statement not covered" > });</span>
2882
+ &nbsp;
2883
+ &nbsp;
2884
+ <span class="cstat-no" title="statement not covered" > const completion = await inferenceClient.chat.completions.create({</span>
2885
+ <span class="cstat-no" title="statement not covered" > model: 'command-a-03-2025',</span>
2886
+ <span class="cstat-no" title="statement not covered" > messages,</span>
2887
+ <span class="cstat-no" title="statement not covered" > temperature: 0.7,</span>
2888
+ <span class="cstat-no" title="statement not covered" > response_format: {</span>
2889
+ <span class="cstat-no" title="statement not covered" > type: "json_object",</span>
2890
+ // @ts-expect-error
2891
+ <span class="cstat-no" title="statement not covered" > schema: {</span>
2892
+ <span class="cstat-no" title="statement not covered" > type: "object",</span>
2893
+ <span class="cstat-no" title="statement not covered" > properties: {</span>
2894
+ <span class="cstat-no" title="statement not covered" > text: { type: "string" },</span>
2895
+ <span class="cstat-no" title="statement not covered" > docs: {</span>
2896
+ <span class="cstat-no" title="statement not covered" > type: "array",</span>
2897
+ <span class="cstat-no" title="statement not covered" > items: {</span>
2898
+ <span class="cstat-no" title="statement not covered" > type: "object",</span>
2899
+ <span class="cstat-no" title="statement not covered" > properties: {</span>
2900
+ <span class="cstat-no" title="statement not covered" > title: { type: "string" },</span>
2901
+ <span class="cstat-no" title="statement not covered" > blocks: {</span>
2902
+ <span class="cstat-no" title="statement not covered" > type: "array",</span>
2903
+ <span class="cstat-no" title="statement not covered" > items: {</span>
2904
+ <span class="cstat-no" title="statement not covered" > type: "object",</span>
2905
+ <span class="cstat-no" title="statement not covered" > properties: {</span>
2906
+ <span class="cstat-no" title="statement not covered" > format: { type: "integer", minimum: 0, maximum: 12 },</span>
2907
+ <span class="cstat-no" title="statement not covered" > content: {</span>
2908
+ <span class="cstat-no" title="statement not covered" > oneOf: [</span>
2909
+ <span class="cstat-no" title="statement not covered" > { type: "string" },</span>
2910
+ <span class="cstat-no" title="statement not covered" > { type: "array", items: { type: "string" } }</span>
2911
+ <span class="cstat-no" title="statement not covered" > ]</span>
2912
+ <span class="cstat-no" title="statement not covered" > },</span>
2913
+ <span class="cstat-no" title="statement not covered" > metadata: {</span>
2914
+ <span class="cstat-no" title="statement not covered" > type: "object",</span>
2915
+ <span class="cstat-no" title="statement not covered" > properties: {</span>
2916
+ <span class="cstat-no" title="statement not covered" > fontSize: { type: "number", minimum: 6 },</span>
2917
+ <span class="cstat-no" title="statement not covered" > lineHeight: { type: "number", minimum: 0.6 },</span>
2918
+ <span class="cstat-no" title="statement not covered" > paragraphSpacing: { type: "number", minimum: 0 },</span>
2919
+ <span class="cstat-no" title="statement not covered" > indentWidth: { type: "number", minimum: 0 },</span>
2920
+ <span class="cstat-no" title="statement not covered" > paddingX: { type: "number", minimum: 0 },</span>
2921
+ <span class="cstat-no" title="statement not covered" > paddingY: { type: "number", minimum: 0 },</span>
2922
+ <span class="cstat-no" title="statement not covered" > font: { type: "integer", minimum: 0, maximum: 5 },</span>
2923
+ <span class="cstat-no" title="statement not covered" > color: { type: "string", pattern: "^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$" },</span>
2924
+ <span class="cstat-no" title="statement not covered" > background: { type: "string", pattern: "^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$" },</span>
2925
+ <span class="cstat-no" title="statement not covered" > align: { type: "string", enum: ["left", "center", "right"] }</span>
2926
+ <span class="cstat-no" title="statement not covered" > },</span>
2927
+ <span class="cstat-no" title="statement not covered" > additionalProperties: false</span>
2928
+ <span class="cstat-no" title="statement not covered" > }</span>
2929
+ <span class="cstat-no" title="statement not covered" > },</span>
2930
+ <span class="cstat-no" title="statement not covered" > required: ["format", "content"],</span>
2931
+ <span class="cstat-no" title="statement not covered" > additionalProperties: false</span>
2932
+ <span class="cstat-no" title="statement not covered" > }</span>
2933
+ <span class="cstat-no" title="statement not covered" > }</span>
2934
+ <span class="cstat-no" title="statement not covered" > },</span>
2935
+ <span class="cstat-no" title="statement not covered" > required: ["title", "blocks"],</span>
2936
+ <span class="cstat-no" title="statement not covered" > additionalProperties: false</span>
2937
+ <span class="cstat-no" title="statement not covered" > }</span>
2938
+ <span class="cstat-no" title="statement not covered" > }</span>
2939
+ <span class="cstat-no" title="statement not covered" > },</span>
2940
+ <span class="cstat-no" title="statement not covered" > required: ["text"],</span>
2941
+ <span class="cstat-no" title="statement not covered" > additionalProperties: false</span>
2942
+ <span class="cstat-no" title="statement not covered" > }</span>
2943
+ <span class="cstat-no" title="statement not covered" > },</span>
2944
+ <span class="cstat-no" title="statement not covered" > });</span>
2945
+ &nbsp;
2946
+ <span class="cstat-no" title="statement not covered" > const response = completion.choices[0]?.message?.content;</span>
2947
+
2948
+ <span class="cstat-no" title="statement not covered" > if (!response) {</span>
2949
+ <span class="cstat-no" title="statement not covered" > throw new Error('No response generated from inference API');</span>
2950
+ <span class="cstat-no" title="statement not covered" > }</span>
2951
+ &nbsp;
2952
+ // Parse the JSON response and generate PDF if docs are provided
2953
+ <span class="cstat-no" title="statement not covered" > try {</span>
2954
+ <span class="cstat-no" title="statement not covered" > const jsonData = JSON.parse(response);</span>
2955
+ &nbsp;
2956
+ &nbsp;
2957
+ <span class="cstat-no" title="statement not covered" > const attachmentIds: string[] = [];</span>
2958
+ // Generate PDFs if docs are provided
2959
+ <span class="cstat-no" title="statement not covered" > if (jsonData.docs &amp;&amp; Array.isArray(jsonData.docs)) {</span>
2960
+
2961
+ &nbsp;
2962
+ <span class="cstat-no" title="statement not covered" > for (let i = 0; i &lt; jsonData.docs.length; i++) {</span>
2963
+ <span class="cstat-no" title="statement not covered" > const doc = jsonData.docs[i];</span>
2964
+ <span class="cstat-no" title="statement not covered" > if (!doc.title || !doc.blocks || !Array.isArray(doc.blocks)) {</span>
2965
+ <span class="cstat-no" title="statement not covered" > logger.error(`Document ${i + 1} is missing title or blocks`);</span>
2966
+ <span class="cstat-no" title="statement not covered" > continue;</span>
2967
+ <span class="cstat-no" title="statement not covered" > } </span>
2968
+ &nbsp;
2969
+ &nbsp;
2970
+ <span class="cstat-no" title="statement not covered" > try {</span>
2971
+ <span class="cstat-no" title="statement not covered" > let pdfBytes = await createPdf(doc.blocks); </span>
2972
+ <span class="cstat-no" title="statement not covered" > if (pdfBytes) {</span>
2973
+ // Sanitize filename - remove special characters and limit length
2974
+ <span class="cstat-no" title="statement not covered" > const sanitizedTitle = doc.title</span>
2975
+ <span class="cstat-no" title="statement not covered" > .replace(/[^a-zA-Z0-9\s\-_]/g, '')</span>
2976
+ <span class="cstat-no" title="statement not covered" > .replace(/\s+/g, '_')</span>
2977
+ <span class="cstat-no" title="statement not covered" > .substring(0, 50);</span>
2978
+
2979
+ <span class="cstat-no" title="statement not covered" > const filename = `${sanitizedTitle}_${uuidv4().substring(0, 8)}.pdf`;</span>
2980
+ <span class="cstat-no" title="statement not covered" > const filePath = `class/generated/${fullLabChat.classId}/${filename}`;</span>
2981
+ &nbsp;
2982
+ <span class="cstat-no" title="statement not covered" > logger.info(`PDF ${i + 1} generated successfully`, { labChatId, title: doc.title });</span>
2983
+
2984
+ // Upload directly to Google Cloud Storage
2985
+ <span class="cstat-no" title="statement not covered" > const gcsFile = bucket.file(filePath);</span>
2986
+ <span class="cstat-no" title="statement not covered" > await gcsFile.save(Buffer.from(pdfBytes), {</span>
2987
+ <span class="cstat-no" title="statement not covered" > metadata: {</span>
2988
+ <span class="cstat-no" title="statement not covered" > contentType: 'application/pdf',</span>
2989
+ <span class="cstat-no" title="statement not covered" > }</span>
2990
+ <span class="cstat-no" title="statement not covered" > });</span>
2991
+
2992
+ <span class="cstat-no" title="statement not covered" > logger.info(`PDF ${i + 1} uploaded successfully`, { labChatId, filename });</span>
2993
+ &nbsp;
2994
+ <span class="cstat-no" title="statement not covered" > const file = await prisma.file.create({</span>
2995
+ <span class="cstat-no" title="statement not covered" > data: {</span>
2996
+ <span class="cstat-no" title="statement not covered" > name: filename,</span>
2997
+ <span class="cstat-no" title="statement not covered" > path: filePath,</span>
2998
+ <span class="cstat-no" title="statement not covered" > type: 'application/pdf',</span>
2999
+ <span class="cstat-no" title="statement not covered" > size: pdfBytes.length,</span>
3000
+ <span class="cstat-no" title="statement not covered" > userId: fullLabChat.createdById,</span>
3001
+ <span class="cstat-no" title="statement not covered" > uploadStatus: 'COMPLETED',</span>
3002
+ <span class="cstat-no" title="statement not covered" > uploadedAt: new Date(),</span>
3003
+ <span class="cstat-no" title="statement not covered" > },</span>
3004
+ <span class="cstat-no" title="statement not covered" > });</span>
3005
+ <span class="cstat-no" title="statement not covered" > attachmentIds.push(file.id);</span>
3006
+ <span class="cstat-no" title="statement not covered" > } else {</span>
3007
+ <span class="cstat-no" title="statement not covered" > logger.error(`PDF ${i + 1} creation returned undefined/null`, { labChatId, title: doc.title });</span>
3008
+ <span class="cstat-no" title="statement not covered" > }</span>
3009
+ <span class="cstat-no" title="statement not covered" > } catch (pdfError) {</span>
3010
+ <span class="cstat-no" title="statement not covered" > logger.error(`PDF creation threw an error for document ${i + 1}:`, { </span>
3011
+ <span class="cstat-no" title="statement not covered" > error: pdfError instanceof Error ? {</span>
3012
+ <span class="cstat-no" title="statement not covered" > message: pdfError.message,</span>
3013
+ <span class="cstat-no" title="statement not covered" > stack: pdfError.stack,</span>
3014
+ <span class="cstat-no" title="statement not covered" > name: pdfError.name</span>
3015
+ <span class="cstat-no" title="statement not covered" > } : pdfError, </span>
3016
+ <span class="cstat-no" title="statement not covered" > labChatId,</span>
3017
+ <span class="cstat-no" title="statement not covered" > title: doc.title</span>
3018
+ <span class="cstat-no" title="statement not covered" > });</span>
3019
+ <span class="cstat-no" title="statement not covered" > }</span>
3020
+ <span class="cstat-no" title="statement not covered" > }</span>
3021
+ <span class="cstat-no" title="statement not covered" > }</span>
3022
+ &nbsp;
3023
+ // Send the text response to the conversation
3024
+ <span class="cstat-no" title="statement not covered" > await sendAIMessage(jsonData.text || response, conversationId, {</span>
3025
+ <span class="cstat-no" title="statement not covered" > attachments: {</span>
3026
+ <span class="cstat-no" title="statement not covered" > connect: attachmentIds.map(id =&gt; ({ id })),</span>
3027
+ <span class="cstat-no" title="statement not covered" > },</span>
3028
+ <span class="cstat-no" title="statement not covered" > subject: fullLabChat.class?.subject || 'Lab',</span>
3029
+ <span class="cstat-no" title="statement not covered" > });</span>
3030
+ <span class="cstat-no" title="statement not covered" > } catch (parseError) {</span>
3031
+ <span class="cstat-no" title="statement not covered" > logger.error('Failed to parse AI response or generate PDF:', { error: parseError, labChatId });</span>
3032
+ // Fallback: send the raw response if parsing fails
3033
+ <span class="cstat-no" title="statement not covered" > await sendAIMessage(response, conversationId, {</span>
3034
+ <span class="cstat-no" title="statement not covered" > subject: fullLabChat.class?.subject || 'Lab',</span>
3035
+ <span class="cstat-no" title="statement not covered" > });</span>
3036
+ <span class="cstat-no" title="statement not covered" > }</span>
3037
+ &nbsp;
3038
+ <span class="cstat-no" title="statement not covered" > logger.info('AI response sent', { labChatId, conversationId });</span>
3039
+ &nbsp;
3040
+ <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
3041
+ <span class="cstat-no" title="statement not covered" > console.error('Full error object:', error);</span>
3042
+ <span class="cstat-no" title="statement not covered" > logger.error('Failed to generate AI response:', { </span>
3043
+ <span class="cstat-no" title="statement not covered" > error: error instanceof Error ? {</span>
3044
+ <span class="cstat-no" title="statement not covered" > message: error.message,</span>
3045
+ <span class="cstat-no" title="statement not covered" > stack: error.stack,</span>
3046
+ <span class="cstat-no" title="statement not covered" > name: error.name</span>
3047
+ <span class="cstat-no" title="statement not covered" > } : error,</span>
3048
+ <span class="cstat-no" title="statement not covered" > labChatId </span>
3049
+ <span class="cstat-no" title="statement not covered" > });</span>
3050
+ <span class="cstat-no" title="statement not covered" > throw error; // Re-throw to see the full error in the calling function</span>
3051
+ <span class="cstat-no" title="statement not covered" > }</span>
3052
+ <span class="cstat-no" title="statement not covered" >}</span>
3053
+ &nbsp;
3054
+ &nbsp;</pre></td></tr></table></pre>
3055
+
3056
+ <div class='push'></div><!-- for sticky footer -->
3057
+ </div><!-- /wrapper -->
3058
+ <div class='footer quiet pad2 space-top1 center small'>
3059
+ Code coverage generated by
3060
+ <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
3061
+ at 2025-11-22T10:42:40.796Z
3062
+ </div>
3063
+ <script src="../../../prettify.js"></script>
3064
+ <script>
3065
+ window.onload = function () {
3066
+ prettyPrint();
3067
+ };
3068
+ </script>
3069
+ <script src="../../../sorter.js"></script>
3070
+ <script src="../../../block-navigation.js"></script>
3071
+ </body>
3072
+ </html>
3073
+