@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,2323 @@
1
+
2
+ <!doctype html>
3
+ <html lang="en">
4
+
5
+ <head>
6
+ <title>Code coverage report for server/src/lib/jsonConversion.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/lib</a> jsonConversion.ts</h1>
23
+ <div class='clearfix'>
24
+
25
+ <div class='fl pad1y space-right2'>
26
+ <span class="strong">0.98% </span>
27
+ <span class="quiet">Statements</span>
28
+ <span class='fraction'>6/608</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/1</span>
43
+ </div>
44
+
45
+
46
+ <div class='fl pad1y space-right2'>
47
+ <span class="strong">0.98% </span>
48
+ <span class="quiet">Lines</span>
49
+ <span class='fraction'>6/608</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></td><td class="line-coverage quiet"><span class="cline-any cline-yes">1x</span>
813
+ <span class="cline-any cline-yes">1x</span>
814
+ <span class="cline-any cline-yes">1x</span>
815
+ <span class="cline-any cline-yes">1x</span>
816
+ <span class="cline-any cline-neutral">&nbsp;</span>
817
+ <span class="cline-any cline-yes">1x</span>
818
+ <span class="cline-any cline-yes">1x</span>
819
+ <span class="cline-any cline-neutral">&nbsp;</span>
820
+ <span class="cline-any cline-no">&nbsp;</span>
821
+ <span class="cline-any cline-no">&nbsp;</span>
822
+ <span class="cline-any cline-no">&nbsp;</span>
823
+ <span class="cline-any cline-no">&nbsp;</span>
824
+ <span class="cline-any cline-no">&nbsp;</span>
825
+ <span class="cline-any cline-neutral">&nbsp;</span>
826
+ <span class="cline-any cline-neutral">&nbsp;</span>
827
+ <span class="cline-any cline-no">&nbsp;</span>
828
+ <span class="cline-any cline-neutral">&nbsp;</span>
829
+ <span class="cline-any cline-neutral">&nbsp;</span>
830
+ <span class="cline-any cline-no">&nbsp;</span>
831
+ <span class="cline-any cline-neutral">&nbsp;</span>
832
+ <span class="cline-any cline-no">&nbsp;</span>
833
+ <span class="cline-any cline-no">&nbsp;</span>
834
+ <span class="cline-any cline-no">&nbsp;</span>
835
+ <span class="cline-any cline-no">&nbsp;</span>
836
+ <span class="cline-any cline-neutral">&nbsp;</span>
837
+ <span class="cline-any cline-no">&nbsp;</span>
838
+ <span class="cline-any cline-neutral">&nbsp;</span>
839
+ <span class="cline-any cline-no">&nbsp;</span>
840
+ <span class="cline-any cline-no">&nbsp;</span>
841
+ <span class="cline-any cline-no">&nbsp;</span>
842
+ <span class="cline-any cline-neutral">&nbsp;</span>
843
+ <span class="cline-any cline-no">&nbsp;</span>
844
+ <span class="cline-any cline-no">&nbsp;</span>
845
+ <span class="cline-any cline-no">&nbsp;</span>
846
+ <span class="cline-any cline-no">&nbsp;</span>
847
+ <span class="cline-any cline-neutral">&nbsp;</span>
848
+ <span class="cline-any cline-no">&nbsp;</span>
849
+ <span class="cline-any cline-no">&nbsp;</span>
850
+ <span class="cline-any cline-no">&nbsp;</span>
851
+ <span class="cline-any cline-neutral">&nbsp;</span>
852
+ <span class="cline-any cline-no">&nbsp;</span>
853
+ <span class="cline-any cline-no">&nbsp;</span>
854
+ <span class="cline-any cline-no">&nbsp;</span>
855
+ <span class="cline-any cline-no">&nbsp;</span>
856
+ <span class="cline-any cline-no">&nbsp;</span>
857
+ <span class="cline-any cline-neutral">&nbsp;</span>
858
+ <span class="cline-any cline-no">&nbsp;</span>
859
+ <span class="cline-any cline-no">&nbsp;</span>
860
+ <span class="cline-any cline-no">&nbsp;</span>
861
+ <span class="cline-any cline-no">&nbsp;</span>
862
+ <span class="cline-any cline-no">&nbsp;</span>
863
+ <span class="cline-any cline-no">&nbsp;</span>
864
+ <span class="cline-any cline-neutral">&nbsp;</span>
865
+ <span class="cline-any cline-no">&nbsp;</span>
866
+ <span class="cline-any cline-no">&nbsp;</span>
867
+ <span class="cline-any cline-neutral">&nbsp;</span>
868
+ <span class="cline-any cline-no">&nbsp;</span>
869
+ <span class="cline-any cline-no">&nbsp;</span>
870
+ <span class="cline-any cline-no">&nbsp;</span>
871
+ <span class="cline-any cline-no">&nbsp;</span>
872
+ <span class="cline-any cline-no">&nbsp;</span>
873
+ <span class="cline-any cline-no">&nbsp;</span>
874
+ <span class="cline-any cline-no">&nbsp;</span>
875
+ <span class="cline-any cline-no">&nbsp;</span>
876
+ <span class="cline-any cline-neutral">&nbsp;</span>
877
+ <span class="cline-any cline-no">&nbsp;</span>
878
+ <span class="cline-any cline-neutral">&nbsp;</span>
879
+ <span class="cline-any cline-no">&nbsp;</span>
880
+ <span class="cline-any cline-no">&nbsp;</span>
881
+ <span class="cline-any cline-no">&nbsp;</span>
882
+ <span class="cline-any cline-no">&nbsp;</span>
883
+ <span class="cline-any cline-no">&nbsp;</span>
884
+ <span class="cline-any cline-no">&nbsp;</span>
885
+ <span class="cline-any cline-no">&nbsp;</span>
886
+ <span class="cline-any cline-no">&nbsp;</span>
887
+ <span class="cline-any cline-no">&nbsp;</span>
888
+ <span class="cline-any cline-no">&nbsp;</span>
889
+ <span class="cline-any cline-no">&nbsp;</span>
890
+ <span class="cline-any cline-no">&nbsp;</span>
891
+ <span class="cline-any cline-no">&nbsp;</span>
892
+ <span class="cline-any cline-no">&nbsp;</span>
893
+ <span class="cline-any cline-no">&nbsp;</span>
894
+ <span class="cline-any cline-neutral">&nbsp;</span>
895
+ <span class="cline-any cline-no">&nbsp;</span>
896
+ <span class="cline-any cline-no">&nbsp;</span>
897
+ <span class="cline-any cline-no">&nbsp;</span>
898
+ <span class="cline-any cline-no">&nbsp;</span>
899
+ <span class="cline-any cline-no">&nbsp;</span>
900
+ <span class="cline-any cline-no">&nbsp;</span>
901
+ <span class="cline-any cline-no">&nbsp;</span>
902
+ <span class="cline-any cline-no">&nbsp;</span>
903
+ <span class="cline-any cline-no">&nbsp;</span>
904
+ <span class="cline-any cline-no">&nbsp;</span>
905
+ <span class="cline-any cline-no">&nbsp;</span>
906
+ <span class="cline-any cline-no">&nbsp;</span>
907
+ <span class="cline-any cline-no">&nbsp;</span>
908
+ <span class="cline-any cline-neutral">&nbsp;</span>
909
+ <span class="cline-any cline-no">&nbsp;</span>
910
+ <span class="cline-any cline-no">&nbsp;</span>
911
+ <span class="cline-any cline-no">&nbsp;</span>
912
+ <span class="cline-any cline-no">&nbsp;</span>
913
+ <span class="cline-any cline-no">&nbsp;</span>
914
+ <span class="cline-any cline-no">&nbsp;</span>
915
+ <span class="cline-any cline-no">&nbsp;</span>
916
+ <span class="cline-any cline-neutral">&nbsp;</span>
917
+ <span class="cline-any cline-neutral">&nbsp;</span>
918
+ <span class="cline-any cline-neutral">&nbsp;</span>
919
+ <span class="cline-any cline-no">&nbsp;</span>
920
+ <span class="cline-any cline-no">&nbsp;</span>
921
+ <span class="cline-any cline-neutral">&nbsp;</span>
922
+ <span class="cline-any cline-no">&nbsp;</span>
923
+ <span class="cline-any cline-no">&nbsp;</span>
924
+ <span class="cline-any cline-no">&nbsp;</span>
925
+ <span class="cline-any cline-no">&nbsp;</span>
926
+ <span class="cline-any cline-no">&nbsp;</span>
927
+ <span class="cline-any cline-neutral">&nbsp;</span>
928
+ <span class="cline-any cline-no">&nbsp;</span>
929
+ <span class="cline-any cline-neutral">&nbsp;</span>
930
+ <span class="cline-any cline-neutral">&nbsp;</span>
931
+ <span class="cline-any cline-neutral">&nbsp;</span>
932
+ <span class="cline-any cline-neutral">&nbsp;</span>
933
+ <span class="cline-any cline-neutral">&nbsp;</span>
934
+ <span class="cline-any cline-neutral">&nbsp;</span>
935
+ <span class="cline-any cline-neutral">&nbsp;</span>
936
+ <span class="cline-any cline-neutral">&nbsp;</span>
937
+ <span class="cline-any cline-no">&nbsp;</span>
938
+ <span class="cline-any cline-no">&nbsp;</span>
939
+ <span class="cline-any cline-no">&nbsp;</span>
940
+ <span class="cline-any cline-neutral">&nbsp;</span>
941
+ <span class="cline-any cline-neutral">&nbsp;</span>
942
+ <span class="cline-any cline-no">&nbsp;</span>
943
+ <span class="cline-any cline-no">&nbsp;</span>
944
+ <span class="cline-any cline-no">&nbsp;</span>
945
+ <span class="cline-any cline-no">&nbsp;</span>
946
+ <span class="cline-any cline-no">&nbsp;</span>
947
+ <span class="cline-any cline-no">&nbsp;</span>
948
+ <span class="cline-any cline-no">&nbsp;</span>
949
+ <span class="cline-any cline-neutral">&nbsp;</span>
950
+ <span class="cline-any cline-neutral">&nbsp;</span>
951
+ <span class="cline-any cline-no">&nbsp;</span>
952
+ <span class="cline-any cline-neutral">&nbsp;</span>
953
+ <span class="cline-any cline-no">&nbsp;</span>
954
+ <span class="cline-any cline-no">&nbsp;</span>
955
+ <span class="cline-any cline-no">&nbsp;</span>
956
+ <span class="cline-any cline-no">&nbsp;</span>
957
+ <span class="cline-any cline-no">&nbsp;</span>
958
+ <span class="cline-any cline-no">&nbsp;</span>
959
+ <span class="cline-any cline-no">&nbsp;</span>
960
+ <span class="cline-any cline-no">&nbsp;</span>
961
+ <span class="cline-any cline-no">&nbsp;</span>
962
+ <span class="cline-any cline-no">&nbsp;</span>
963
+ <span class="cline-any cline-no">&nbsp;</span>
964
+ <span class="cline-any cline-no">&nbsp;</span>
965
+ <span class="cline-any cline-no">&nbsp;</span>
966
+ <span class="cline-any cline-neutral">&nbsp;</span>
967
+ <span class="cline-any cline-neutral">&nbsp;</span>
968
+ <span class="cline-any cline-no">&nbsp;</span>
969
+ <span class="cline-any cline-neutral">&nbsp;</span>
970
+ <span class="cline-any cline-neutral">&nbsp;</span>
971
+ <span class="cline-any cline-no">&nbsp;</span>
972
+ <span class="cline-any cline-no">&nbsp;</span>
973
+ <span class="cline-any cline-no">&nbsp;</span>
974
+ <span class="cline-any cline-no">&nbsp;</span>
975
+ <span class="cline-any cline-no">&nbsp;</span>
976
+ <span class="cline-any cline-no">&nbsp;</span>
977
+ <span class="cline-any cline-no">&nbsp;</span>
978
+ <span class="cline-any cline-no">&nbsp;</span>
979
+ <span class="cline-any cline-no">&nbsp;</span>
980
+ <span class="cline-any cline-neutral">&nbsp;</span>
981
+ <span class="cline-any cline-neutral">&nbsp;</span>
982
+ <span class="cline-any cline-no">&nbsp;</span>
983
+ <span class="cline-any cline-neutral">&nbsp;</span>
984
+ <span class="cline-any cline-no">&nbsp;</span>
985
+ <span class="cline-any cline-no">&nbsp;</span>
986
+ <span class="cline-any cline-no">&nbsp;</span>
987
+ <span class="cline-any cline-no">&nbsp;</span>
988
+ <span class="cline-any cline-no">&nbsp;</span>
989
+ <span class="cline-any cline-no">&nbsp;</span>
990
+ <span class="cline-any cline-no">&nbsp;</span>
991
+ <span class="cline-any cline-no">&nbsp;</span>
992
+ <span class="cline-any cline-no">&nbsp;</span>
993
+ <span class="cline-any cline-no">&nbsp;</span>
994
+ <span class="cline-any cline-neutral">&nbsp;</span>
995
+ <span class="cline-any cline-neutral">&nbsp;</span>
996
+ <span class="cline-any cline-no">&nbsp;</span>
997
+ <span class="cline-any cline-no">&nbsp;</span>
998
+ <span class="cline-any cline-no">&nbsp;</span>
999
+ <span class="cline-any cline-no">&nbsp;</span>
1000
+ <span class="cline-any cline-no">&nbsp;</span>
1001
+ <span class="cline-any cline-neutral">&nbsp;</span>
1002
+ <span class="cline-any cline-no">&nbsp;</span>
1003
+ <span class="cline-any cline-no">&nbsp;</span>
1004
+ <span class="cline-any cline-neutral">&nbsp;</span>
1005
+ <span class="cline-any cline-neutral">&nbsp;</span>
1006
+ <span class="cline-any cline-no">&nbsp;</span>
1007
+ <span class="cline-any cline-no">&nbsp;</span>
1008
+ <span class="cline-any cline-no">&nbsp;</span>
1009
+ <span class="cline-any cline-no">&nbsp;</span>
1010
+ <span class="cline-any cline-no">&nbsp;</span>
1011
+ <span class="cline-any cline-no">&nbsp;</span>
1012
+ <span class="cline-any cline-no">&nbsp;</span>
1013
+ <span class="cline-any cline-no">&nbsp;</span>
1014
+ <span class="cline-any cline-no">&nbsp;</span>
1015
+ <span class="cline-any cline-no">&nbsp;</span>
1016
+ <span class="cline-any cline-neutral">&nbsp;</span>
1017
+ <span class="cline-any cline-neutral">&nbsp;</span>
1018
+ <span class="cline-any cline-no">&nbsp;</span>
1019
+ <span class="cline-any cline-no">&nbsp;</span>
1020
+ <span class="cline-any cline-no">&nbsp;</span>
1021
+ <span class="cline-any cline-no">&nbsp;</span>
1022
+ <span class="cline-any cline-no">&nbsp;</span>
1023
+ <span class="cline-any cline-no">&nbsp;</span>
1024
+ <span class="cline-any cline-no">&nbsp;</span>
1025
+ <span class="cline-any cline-neutral">&nbsp;</span>
1026
+ <span class="cline-any cline-no">&nbsp;</span>
1027
+ <span class="cline-any cline-no">&nbsp;</span>
1028
+ <span class="cline-any cline-neutral">&nbsp;</span>
1029
+ <span class="cline-any cline-neutral">&nbsp;</span>
1030
+ <span class="cline-any cline-no">&nbsp;</span>
1031
+ <span class="cline-any cline-no">&nbsp;</span>
1032
+ <span class="cline-any cline-no">&nbsp;</span>
1033
+ <span class="cline-any cline-no">&nbsp;</span>
1034
+ <span class="cline-any cline-neutral">&nbsp;</span>
1035
+ <span class="cline-any cline-no">&nbsp;</span>
1036
+ <span class="cline-any cline-no">&nbsp;</span>
1037
+ <span class="cline-any cline-no">&nbsp;</span>
1038
+ <span class="cline-any cline-neutral">&nbsp;</span>
1039
+ <span class="cline-any cline-no">&nbsp;</span>
1040
+ <span class="cline-any cline-no">&nbsp;</span>
1041
+ <span class="cline-any cline-no">&nbsp;</span>
1042
+ <span class="cline-any cline-no">&nbsp;</span>
1043
+ <span class="cline-any cline-neutral">&nbsp;</span>
1044
+ <span class="cline-any cline-neutral">&nbsp;</span>
1045
+ <span class="cline-any cline-neutral">&nbsp;</span>
1046
+ <span class="cline-any cline-neutral">&nbsp;</span>
1047
+ <span class="cline-any cline-no">&nbsp;</span>
1048
+ <span class="cline-any cline-no">&nbsp;</span>
1049
+ <span class="cline-any cline-neutral">&nbsp;</span>
1050
+ <span class="cline-any cline-neutral">&nbsp;</span>
1051
+ <span class="cline-any cline-no">&nbsp;</span>
1052
+ <span class="cline-any cline-neutral">&nbsp;</span>
1053
+ <span class="cline-any cline-no">&nbsp;</span>
1054
+ <span class="cline-any cline-no">&nbsp;</span>
1055
+ <span class="cline-any cline-no">&nbsp;</span>
1056
+ <span class="cline-any cline-no">&nbsp;</span>
1057
+ <span class="cline-any cline-neutral">&nbsp;</span>
1058
+ <span class="cline-any cline-neutral">&nbsp;</span>
1059
+ <span class="cline-any cline-no">&nbsp;</span>
1060
+ <span class="cline-any cline-neutral">&nbsp;</span>
1061
+ <span class="cline-any cline-no">&nbsp;</span>
1062
+ <span class="cline-any cline-no">&nbsp;</span>
1063
+ <span class="cline-any cline-no">&nbsp;</span>
1064
+ <span class="cline-any cline-no">&nbsp;</span>
1065
+ <span class="cline-any cline-no">&nbsp;</span>
1066
+ <span class="cline-any cline-neutral">&nbsp;</span>
1067
+ <span class="cline-any cline-no">&nbsp;</span>
1068
+ <span class="cline-any cline-no">&nbsp;</span>
1069
+ <span class="cline-any cline-no">&nbsp;</span>
1070
+ <span class="cline-any cline-no">&nbsp;</span>
1071
+ <span class="cline-any cline-neutral">&nbsp;</span>
1072
+ <span class="cline-any cline-no">&nbsp;</span>
1073
+ <span class="cline-any cline-no">&nbsp;</span>
1074
+ <span class="cline-any cline-no">&nbsp;</span>
1075
+ <span class="cline-any cline-no">&nbsp;</span>
1076
+ <span class="cline-any cline-no">&nbsp;</span>
1077
+ <span class="cline-any cline-neutral">&nbsp;</span>
1078
+ <span class="cline-any cline-neutral">&nbsp;</span>
1079
+ <span class="cline-any cline-no">&nbsp;</span>
1080
+ <span class="cline-any cline-no">&nbsp;</span>
1081
+ <span class="cline-any cline-no">&nbsp;</span>
1082
+ <span class="cline-any cline-neutral">&nbsp;</span>
1083
+ <span class="cline-any cline-no">&nbsp;</span>
1084
+ <span class="cline-any cline-no">&nbsp;</span>
1085
+ <span class="cline-any cline-neutral">&nbsp;</span>
1086
+ <span class="cline-any cline-no">&nbsp;</span>
1087
+ <span class="cline-any cline-no">&nbsp;</span>
1088
+ <span class="cline-any cline-no">&nbsp;</span>
1089
+ <span class="cline-any cline-neutral">&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-no">&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-neutral">&nbsp;</span>
1098
+ <span class="cline-any cline-no">&nbsp;</span>
1099
+ <span class="cline-any cline-neutral">&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-neutral">&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-neutral">&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-no">&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-neutral">&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-no">&nbsp;</span>
1137
+ <span class="cline-any cline-no">&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-no">&nbsp;</span>
1147
+ <span class="cline-any cline-no">&nbsp;</span>
1148
+ <span class="cline-any cline-no">&nbsp;</span>
1149
+ <span class="cline-any cline-no">&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-neutral">&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-no">&nbsp;</span>
1158
+ <span class="cline-any cline-no">&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-neutral">&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-neutral">&nbsp;</span>
1171
+ <span class="cline-any cline-no">&nbsp;</span>
1172
+ <span class="cline-any cline-no">&nbsp;</span>
1173
+ <span class="cline-any cline-neutral">&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-neutral">&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-neutral">&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-neutral">&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-neutral">&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-neutral">&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-neutral">&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-neutral">&nbsp;</span>
1222
+ <span class="cline-any cline-no">&nbsp;</span>
1223
+ <span class="cline-any cline-no">&nbsp;</span>
1224
+ <span class="cline-any cline-no">&nbsp;</span>
1225
+ <span class="cline-any cline-neutral">&nbsp;</span>
1226
+ <span class="cline-any cline-no">&nbsp;</span>
1227
+ <span class="cline-any cline-no">&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-no">&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-no">&nbsp;</span>
1245
+ <span class="cline-any cline-no">&nbsp;</span>
1246
+ <span class="cline-any cline-no">&nbsp;</span>
1247
+ <span class="cline-any cline-no">&nbsp;</span>
1248
+ <span class="cline-any cline-neutral">&nbsp;</span>
1249
+ <span class="cline-any cline-no">&nbsp;</span>
1250
+ <span class="cline-any cline-no">&nbsp;</span>
1251
+ <span class="cline-any cline-no">&nbsp;</span>
1252
+ <span class="cline-any cline-no">&nbsp;</span>
1253
+ <span class="cline-any cline-no">&nbsp;</span>
1254
+ <span class="cline-any cline-neutral">&nbsp;</span>
1255
+ <span class="cline-any cline-no">&nbsp;</span>
1256
+ <span class="cline-any cline-no">&nbsp;</span>
1257
+ <span class="cline-any cline-no">&nbsp;</span>
1258
+ <span class="cline-any cline-neutral">&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-neutral">&nbsp;</span>
1263
+ <span class="cline-any cline-neutral">&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-neutral">&nbsp;</span>
1274
+ <span class="cline-any cline-neutral">&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-neutral">&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-neutral">&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-neutral">&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-neutral">&nbsp;</span>
1310
+ <span class="cline-any cline-neutral">&nbsp;</span>
1311
+ <span class="cline-any cline-no">&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-neutral">&nbsp;</span>
1321
+ <span class="cline-any cline-neutral">&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-no">&nbsp;</span>
1333
+ <span class="cline-any cline-no">&nbsp;</span>
1334
+ <span class="cline-any cline-no">&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-neutral">&nbsp;</span>
1341
+ <span class="cline-any cline-no">&nbsp;</span>
1342
+ <span class="cline-any cline-no">&nbsp;</span>
1343
+ <span class="cline-any cline-no">&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-neutral">&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-neutral">&nbsp;</span>
1365
+ <span class="cline-any cline-neutral">&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-neutral">&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-neutral">&nbsp;</span>
1387
+ <span class="cline-any cline-neutral">&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-neutral">&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-no">&nbsp;</span>
1400
+ <span class="cline-any cline-no">&nbsp;</span>
1401
+ <span class="cline-any cline-no">&nbsp;</span>
1402
+ <span class="cline-any cline-no">&nbsp;</span>
1403
+ <span class="cline-any cline-no">&nbsp;</span>
1404
+ <span class="cline-any cline-neutral">&nbsp;</span>
1405
+ <span class="cline-any cline-neutral">&nbsp;</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-no">&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-neutral">&nbsp;</span>
1417
+ <span class="cline-any cline-no">&nbsp;</span>
1418
+ <span class="cline-any cline-neutral">&nbsp;</span>
1419
+ <span class="cline-any cline-neutral">&nbsp;</span>
1420
+ <span class="cline-any cline-no">&nbsp;</span>
1421
+ <span class="cline-any cline-neutral">&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-neutral">&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-neutral">&nbsp;</span>
1430
+ <span class="cline-any cline-no">&nbsp;</span>
1431
+ <span class="cline-any cline-no">&nbsp;</span>
1432
+ <span class="cline-any cline-no">&nbsp;</span>
1433
+ <span class="cline-any cline-neutral">&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-no">&nbsp;</span>
1439
+ <span class="cline-any cline-no">&nbsp;</span>
1440
+ <span class="cline-any cline-neutral">&nbsp;</span>
1441
+ <span class="cline-any cline-neutral">&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-neutral">&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-neutral">&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-neutral">&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-neutral">&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-neutral">&nbsp;</span>
1484
+ <span class="cline-any cline-neutral">&nbsp;</span>
1485
+ <span class="cline-any cline-no">&nbsp;</span>
1486
+ <span class="cline-any cline-neutral">&nbsp;</span>
1487
+ <span class="cline-any cline-no">&nbsp;</span>
1488
+ <span class="cline-any cline-no">&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-neutral">&nbsp;</span>
1499
+ <span class="cline-any cline-neutral">&nbsp;</span>
1500
+ <span class="cline-any cline-no">&nbsp;</span>
1501
+ <span class="cline-any cline-no">&nbsp;</span>
1502
+ <span class="cline-any cline-no">&nbsp;</span>
1503
+ <span class="cline-any cline-no">&nbsp;</span>
1504
+ <span class="cline-any cline-no">&nbsp;</span>
1505
+ <span class="cline-any cline-no">&nbsp;</span>
1506
+ <span class="cline-any cline-no">&nbsp;</span>
1507
+ <span class="cline-any cline-no">&nbsp;</span>
1508
+ <span class="cline-any cline-no">&nbsp;</span>
1509
+ <span class="cline-any cline-no">&nbsp;</span>
1510
+ <span class="cline-any cline-no">&nbsp;</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-no">&nbsp;</span>
1514
+ <span class="cline-any cline-no">&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-no">&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-no">&nbsp;</span>
1542
+ <span class="cline-any cline-no">&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-neutral">&nbsp;</span>
1549
+ <span class="cline-any cline-no">&nbsp;</span>
1550
+ <span class="cline-any cline-no">&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></td><td class="text"><pre class="prettyprint lang-js">import { PDFDocument, PDFFont, RGB, StandardFonts, last, rgb } from 'pdf-lib'
1559
+ import fontkit from '@pdf-lib/fontkit'
1560
+ import { readFileSync } from 'fs'
1561
+ import { join } from 'path'
1562
+ import { writeFile } from 'fs'
1563
+ import { DocumentBlock, FormatTypes, Fonts } from './jsonStyles.js'
1564
+ import { logger } from 'src/utils/logger.js'
1565
+ &nbsp;
1566
+ <span class="cstat-no" title="statement not covered" ><span class="fstat-no" title="function not covered" >export async function createPdf(blocks: DocumentBlock[]) {</span></span>
1567
+ <span class="cstat-no" title="statement not covered" > logger.info(`createPdf: Starting PDF creation with ${blocks.length} blocks`);</span>
1568
+ <span class="cstat-no" title="statement not covered" > try {</span>
1569
+ <span class="cstat-no" title="statement not covered" > const pdfDoc = await PDFDocument.create()</span>
1570
+ <span class="cstat-no" title="statement not covered" > logger.info('createPdf: PDFDocument created successfully');</span>
1571
+
1572
+ // Register fontkit to enable custom font embedding
1573
+ <span class="cstat-no" title="statement not covered" > pdfDoc.registerFontkit(fontkit)</span>
1574
+
1575
+ // Load Unicode-compatible fonts (Noto Sans)
1576
+ <span class="cstat-no" title="statement not covered" > const fontDir = join(process.cwd(), 'src', 'lib')</span>
1577
+
1578
+ <span class="cstat-no" title="statement not covered" > let notoSansRegular: PDFFont</span>
1579
+ <span class="cstat-no" title="statement not covered" > let notoSansBold: PDFFont</span>
1580
+ <span class="cstat-no" title="statement not covered" > let notoSansItalic: PDFFont</span>
1581
+ <span class="cstat-no" title="statement not covered" > let courierFont: PDFFont</span>
1582
+
1583
+ <span class="cstat-no" title="statement not covered" > try {</span>
1584
+ // Try to load custom Unicode fonts
1585
+ <span class="cstat-no" title="statement not covered" > const regularFontBytes = readFileSync(join(fontDir, 'NotoSans-Regular.ttf'))</span>
1586
+ <span class="cstat-no" title="statement not covered" > const boldFontBytes = readFileSync(join(fontDir, 'NotoSans-Bold.ttf'))</span>
1587
+ <span class="cstat-no" title="statement not covered" > const italicFontBytes = readFileSync(join(fontDir, 'NotoSans-Italic.ttf'))</span>
1588
+
1589
+ <span class="cstat-no" title="statement not covered" > notoSansRegular = await pdfDoc.embedFont(regularFontBytes)</span>
1590
+ <span class="cstat-no" title="statement not covered" > notoSansBold = await pdfDoc.embedFont(boldFontBytes)</span>
1591
+ <span class="cstat-no" title="statement not covered" > notoSansItalic = await pdfDoc.embedFont(italicFontBytes)</span>
1592
+ <span class="cstat-no" title="statement not covered" > courierFont = await pdfDoc.embedFont(StandardFonts.Courier) // Keep Courier for code blocks</span>
1593
+
1594
+ <span class="cstat-no" title="statement not covered" > logger.info('createPdf: Unicode fonts loaded successfully');</span>
1595
+ <span class="cstat-no" title="statement not covered" > } catch (fontError) {</span>
1596
+ <span class="cstat-no" title="statement not covered" > logger.warn(`createPdf: Failed to load custom fonts, falling back to standard fonts: ${fontError}`);</span>
1597
+ // Fallback to standard fonts if custom fonts fail
1598
+ <span class="cstat-no" title="statement not covered" > notoSansRegular = await pdfDoc.embedFont(StandardFonts.Helvetica)</span>
1599
+ <span class="cstat-no" title="statement not covered" > notoSansBold = await pdfDoc.embedFont(StandardFonts.HelveticaBold)</span>
1600
+ <span class="cstat-no" title="statement not covered" > notoSansItalic = await pdfDoc.embedFont(StandardFonts.HelveticaOblique)</span>
1601
+ <span class="cstat-no" title="statement not covered" > courierFont = await pdfDoc.embedFont(StandardFonts.Courier)</span>
1602
+ <span class="cstat-no" title="statement not covered" > }</span>
1603
+ &nbsp;
1604
+ <span class="cstat-no" title="statement not covered" > const defaultFont = notoSansRegular</span>
1605
+ <span class="cstat-no" title="statement not covered" > const defaultParagraphSpacing = 10;</span>
1606
+ <span class="cstat-no" title="statement not covered" > const defaultLineHeight = 1.3</span>
1607
+ <span class="cstat-no" title="statement not covered" > const defaultFontSize = 12</span>
1608
+ <span class="cstat-no" title="statement not covered" > const defaultIndentWidth = 14</span>
1609
+ <span class="cstat-no" title="statement not covered" > const defaultPadding = 10</span>
1610
+ &nbsp;
1611
+ <span class="cstat-no" title="statement not covered" > const headingColor = rgb(0.1, 0.1, 0.1)</span>
1612
+ <span class="cstat-no" title="statement not covered" > const paragraphColor = rgb(0.15, 0.15, 0.15)</span>
1613
+ &nbsp;
1614
+ <span class="cstat-no" title="statement not covered" > const FONTS: Record&lt;number, PDFFont&gt; = {</span>
1615
+ <span class="cstat-no" title="statement not covered" > [Fonts.TIMES_ROMAN]: notoSansRegular, // Use Noto Sans instead of Times</span>
1616
+ <span class="cstat-no" title="statement not covered" > [Fonts.COURIER]: courierFont,</span>
1617
+ <span class="cstat-no" title="statement not covered" > [Fonts.HELVETICA]: notoSansRegular,</span>
1618
+ <span class="cstat-no" title="statement not covered" > [Fonts.HELVETICA_BOLD]: notoSansBold,</span>
1619
+ <span class="cstat-no" title="statement not covered" > [Fonts.HELVETICA_ITALIC]: notoSansItalic,</span>
1620
+ <span class="cstat-no" title="statement not covered" > [Fonts.HELVETICA_BOLD_ITALIC]: notoSansBold, // Use bold for now, could add bold-italic later</span>
1621
+ <span class="cstat-no" title="statement not covered" > }</span>
1622
+ &nbsp;
1623
+ <span class="cstat-no" title="statement not covered" > const STYLE_PRESETS: Record&lt;number,</span>
1624
+ { fontSize: number; lineHeight: number; paragraphSpacing?: number; font?: PDFFont; color?: RGB; background?: RGB }&gt; =
1625
+ <span class="cstat-no" title="statement not covered" > {</span>
1626
+ <span class="cstat-no" title="statement not covered" > [FormatTypes.HEADER_1]: { fontSize: 28, lineHeight: 1.35, font: notoSansBold, color: headingColor },</span>
1627
+ <span class="cstat-no" title="statement not covered" > [FormatTypes.HEADER_2]: { fontSize: 22, lineHeight: 1.35, font: notoSansBold, color: headingColor },</span>
1628
+ <span class="cstat-no" title="statement not covered" > [FormatTypes.HEADER_3]: { fontSize: 18, lineHeight: 1.35, font: notoSansBold, color: headingColor },</span>
1629
+ <span class="cstat-no" title="statement not covered" > [FormatTypes.HEADER_4]: { fontSize: 16, lineHeight: 1.3, font: notoSansBold, color: headingColor },</span>
1630
+ <span class="cstat-no" title="statement not covered" > [FormatTypes.HEADER_5]: { fontSize: 14, lineHeight: 1.3, font: notoSansBold, color: headingColor },</span>
1631
+ <span class="cstat-no" title="statement not covered" > [FormatTypes.HEADER_6]: { fontSize: 12, lineHeight: 1.3, font: notoSansBold, color: headingColor },</span>
1632
+ <span class="cstat-no" title="statement not covered" > [FormatTypes.QUOTE]: { fontSize: 14, lineHeight: 1.5, color: rgb(0.35, 0.35, 0.35) },</span>
1633
+ <span class="cstat-no" title="statement not covered" > [FormatTypes.CODE_BLOCK]: { fontSize: 12, lineHeight: 1.6, font: courierFont, color: rgb(0.1, 0.1, 0.1), background: rgb(0.95, 0.95, 0.95) },</span>
1634
+ <span class="cstat-no" title="statement not covered" > [FormatTypes.PARAGRAPH]: { fontSize: 12, lineHeight: 1.3, color: paragraphColor },</span>
1635
+ <span class="cstat-no" title="statement not covered" > [FormatTypes.BULLET]: { fontSize: 12, lineHeight: 1.3, color: paragraphColor },</span>
1636
+ <span class="cstat-no" title="statement not covered" > [FormatTypes.NUMBERED]: { fontSize: 12, lineHeight: 1.3, color: paragraphColor },</span>
1637
+ <span class="cstat-no" title="statement not covered" > [FormatTypes.TABLE]: { fontSize: 12, lineHeight: 1.3, color: paragraphColor },</span>
1638
+ <span class="cstat-no" title="statement not covered" > [FormatTypes.IMAGE]: { fontSize: 12, lineHeight: 1.3 },</span>
1639
+ <span class="cstat-no" title="statement not covered" > }</span>
1640
+ &nbsp;
1641
+ <span class="cstat-no" title="statement not covered" > const hexToRgb = (hex) =&gt; {</span>
1642
+ <span class="cstat-no" title="statement not covered" > if (hex.length == 7) {</span>
1643
+ <span class="cstat-no" title="statement not covered" > const r = parseInt(hex.slice(1, 3), 16) / 255.0;</span>
1644
+ <span class="cstat-no" title="statement not covered" > const g = parseInt(hex.slice(3, 5), 16) / 255.0;</span>
1645
+ <span class="cstat-no" title="statement not covered" > const b = parseInt(hex.slice(5, 7), 16) / 255.0;</span>
1646
+ <span class="cstat-no" title="statement not covered" > return rgb(r, g, b);</span>
1647
+ <span class="cstat-no" title="statement not covered" > } else if (hex.length == 4) {</span>
1648
+ <span class="cstat-no" title="statement not covered" > const r = parseInt(hex.slice(1, 2), 16) / 15.0;</span>
1649
+ <span class="cstat-no" title="statement not covered" > const g = parseInt(hex.slice(2, 3), 16) / 15.0;</span>
1650
+ <span class="cstat-no" title="statement not covered" > const b = parseInt(hex.slice(3, 4), 16) / 15.0;</span>
1651
+ <span class="cstat-no" title="statement not covered" > return rgb(r, g, b);</span>
1652
+ <span class="cstat-no" title="statement not covered" > } else { return rgb(0.0, 0.0, 0.0) };</span>
1653
+ <span class="cstat-no" title="statement not covered" > };</span>
1654
+ &nbsp;
1655
+ <span class="cstat-no" title="statement not covered" > const colorParse = (color) =&gt; {</span>
1656
+ <span class="cstat-no" title="statement not covered" > if (typeof color === 'string') {</span>
1657
+ <span class="cstat-no" title="statement not covered" > return hexToRgb(color)</span>
1658
+ <span class="cstat-no" title="statement not covered" > } else {</span>
1659
+ <span class="cstat-no" title="statement not covered" > return color</span>
1660
+ <span class="cstat-no" title="statement not covered" > }</span>
1661
+ <span class="cstat-no" title="statement not covered" > }</span>
1662
+ &nbsp;
1663
+ // Minimal sanitization - only remove truly problematic invisible characters
1664
+ // With Unicode fonts, we can now keep most characters as-is
1665
+ <span class="cstat-no" title="statement not covered" > const sanitizeText = (text: string): string =&gt; {</span>
1666
+ <span class="cstat-no" title="statement not covered" > return text</span>
1667
+ // Only remove invisible/control characters that break PDF generation
1668
+ <span class="cstat-no" title="statement not covered" > .replace(/\uFEFF/g, '') // Remove BOM (Byte Order Mark)</span>
1669
+ <span class="cstat-no" title="statement not covered" > .replace(/\u200B/g, '') // Remove zero-width space</span>
1670
+ <span class="cstat-no" title="statement not covered" > .replace(/\u200C/g, '') // Remove zero-width non-joiner</span>
1671
+ <span class="cstat-no" title="statement not covered" > .replace(/\u200D/g, '') // Remove zero-width joiner</span>
1672
+ <span class="cstat-no" title="statement not covered" > .replace(/\uFFFD/g, '?') // Replace replacement character with ?</span>
1673
+ // Keep ALL visible Unicode characters - Noto Sans supports them!
1674
+ <span class="cstat-no" title="statement not covered" > }</span>
1675
+ &nbsp;
1676
+ // Parse markdown and return styled text segments
1677
+ interface TextSegment {
1678
+ text: string;
1679
+ font: PDFFont;
1680
+ color: RGB;
1681
+ }
1682
+ &nbsp;
1683
+ <span class="cstat-no" title="statement not covered" > const parseMarkdown = (text: string, baseFont: PDFFont, baseColor: RGB): TextSegment[] =&gt; {</span>
1684
+ <span class="cstat-no" title="statement not covered" > const segments: TextSegment[] = [];</span>
1685
+ <span class="cstat-no" title="statement not covered" > let currentIndex = 0;</span>
1686
+
1687
+ // Regex patterns for markdown
1688
+ <span class="cstat-no" title="statement not covered" > const patterns = [</span>
1689
+ <span class="cstat-no" title="statement not covered" > { regex: /\*\*(.*?)\*\*/g, font: notoSansBold }, // **bold**</span>
1690
+ <span class="cstat-no" title="statement not covered" > { regex: /__(.*?)__/g, font: notoSansBold }, // __bold__</span>
1691
+ <span class="cstat-no" title="statement not covered" > { regex: /\*(.*?)\*/g, font: notoSansItalic }, // *italic*</span>
1692
+ <span class="cstat-no" title="statement not covered" > { regex: /_(.*?)_/g, font: notoSansItalic }, // _italic_</span>
1693
+ <span class="cstat-no" title="statement not covered" > { regex: /`(.*?)`/g, font: courierFont, color: rgb(0.2, 0.2, 0.2) }, // `code`</span>
1694
+ <span class="cstat-no" title="statement not covered" > ];</span>
1695
+ &nbsp;
1696
+ // Find all markdown matches
1697
+ <span class="cstat-no" title="statement not covered" > const matches: Array&lt;{start: number, end: number, text: string, font: PDFFont, color?: RGB}&gt; = [];</span>
1698
+
1699
+ <span class="cstat-no" title="statement not covered" > for (const pattern of patterns) {</span>
1700
+ <span class="cstat-no" title="statement not covered" > let match;</span>
1701
+ <span class="cstat-no" title="statement not covered" > pattern.regex.lastIndex = 0; // Reset regex</span>
1702
+ <span class="cstat-no" title="statement not covered" > while ((match = pattern.regex.exec(text)) !== null) {</span>
1703
+ <span class="cstat-no" title="statement not covered" > matches.push({</span>
1704
+ <span class="cstat-no" title="statement not covered" > start: match.index,</span>
1705
+ <span class="cstat-no" title="statement not covered" > end: match.index + match[0].length,</span>
1706
+ <span class="cstat-no" title="statement not covered" > text: match[1], // Captured group (content without markdown syntax)</span>
1707
+ <span class="cstat-no" title="statement not covered" > font: pattern.font,</span>
1708
+ <span class="cstat-no" title="statement not covered" > color: pattern.color</span>
1709
+ <span class="cstat-no" title="statement not covered" > });</span>
1710
+ <span class="cstat-no" title="statement not covered" > }</span>
1711
+ <span class="cstat-no" title="statement not covered" > }</span>
1712
+ &nbsp;
1713
+ // Sort matches by start position
1714
+ <span class="cstat-no" title="statement not covered" > matches.sort((a, b) =&gt; a.start - b.start);</span>
1715
+ &nbsp;
1716
+ // Remove overlapping matches (keep the first one)
1717
+ <span class="cstat-no" title="statement not covered" > const filteredMatches: Array&lt;{start: number, end: number, text: string, font: PDFFont, color?: RGB}&gt; = [];</span>
1718
+ <span class="cstat-no" title="statement not covered" > for (const match of matches) {</span>
1719
+ <span class="cstat-no" title="statement not covered" > const hasOverlap = filteredMatches.some(existing =&gt; </span>
1720
+ <span class="cstat-no" title="statement not covered" > (match.start &lt; existing.end &amp;&amp; match.end &gt; existing.start)</span>
1721
+ <span class="cstat-no" title="statement not covered" > );</span>
1722
+ <span class="cstat-no" title="statement not covered" > if (!hasOverlap) {</span>
1723
+ <span class="cstat-no" title="statement not covered" > filteredMatches.push(match);</span>
1724
+ <span class="cstat-no" title="statement not covered" > }</span>
1725
+ <span class="cstat-no" title="statement not covered" > }</span>
1726
+ &nbsp;
1727
+ // Build segments
1728
+ <span class="cstat-no" title="statement not covered" > for (const match of filteredMatches) {</span>
1729
+ // Add text before this match
1730
+ <span class="cstat-no" title="statement not covered" > if (match.start &gt; currentIndex) {</span>
1731
+ <span class="cstat-no" title="statement not covered" > const beforeText = text.substring(currentIndex, match.start);</span>
1732
+ <span class="cstat-no" title="statement not covered" > if (beforeText) {</span>
1733
+ <span class="cstat-no" title="statement not covered" > segments.push({</span>
1734
+ <span class="cstat-no" title="statement not covered" > text: sanitizeText(beforeText),</span>
1735
+ <span class="cstat-no" title="statement not covered" > font: baseFont,</span>
1736
+ <span class="cstat-no" title="statement not covered" > color: baseColor</span>
1737
+ <span class="cstat-no" title="statement not covered" > });</span>
1738
+ <span class="cstat-no" title="statement not covered" > }</span>
1739
+ <span class="cstat-no" title="statement not covered" > }</span>
1740
+ &nbsp;
1741
+ // Add the styled match
1742
+ <span class="cstat-no" title="statement not covered" > segments.push({</span>
1743
+ <span class="cstat-no" title="statement not covered" > text: sanitizeText(match.text),</span>
1744
+ <span class="cstat-no" title="statement not covered" > font: match.font,</span>
1745
+ <span class="cstat-no" title="statement not covered" > color: match.color || baseColor</span>
1746
+ <span class="cstat-no" title="statement not covered" > });</span>
1747
+ &nbsp;
1748
+ <span class="cstat-no" title="statement not covered" > currentIndex = match.end;</span>
1749
+ <span class="cstat-no" title="statement not covered" > }</span>
1750
+ &nbsp;
1751
+ // Add remaining text
1752
+ <span class="cstat-no" title="statement not covered" > if (currentIndex &lt; text.length) {</span>
1753
+ <span class="cstat-no" title="statement not covered" > const remainingText = text.substring(currentIndex);</span>
1754
+ <span class="cstat-no" title="statement not covered" > if (remainingText) {</span>
1755
+ <span class="cstat-no" title="statement not covered" > segments.push({</span>
1756
+ <span class="cstat-no" title="statement not covered" > text: sanitizeText(remainingText),</span>
1757
+ <span class="cstat-no" title="statement not covered" > font: baseFont,</span>
1758
+ <span class="cstat-no" title="statement not covered" > color: baseColor</span>
1759
+ <span class="cstat-no" title="statement not covered" > });</span>
1760
+ <span class="cstat-no" title="statement not covered" > }</span>
1761
+ <span class="cstat-no" title="statement not covered" > }</span>
1762
+ &nbsp;
1763
+ // If no markdown was found, return the whole text as one segment
1764
+ <span class="cstat-no" title="statement not covered" > if (segments.length === 0) {</span>
1765
+ <span class="cstat-no" title="statement not covered" > segments.push({</span>
1766
+ <span class="cstat-no" title="statement not covered" > text: sanitizeText(text),</span>
1767
+ <span class="cstat-no" title="statement not covered" > font: baseFont,</span>
1768
+ <span class="cstat-no" title="statement not covered" > color: baseColor</span>
1769
+ <span class="cstat-no" title="statement not covered" > });</span>
1770
+ <span class="cstat-no" title="statement not covered" > }</span>
1771
+ &nbsp;
1772
+ <span class="cstat-no" title="statement not covered" > return segments;</span>
1773
+ <span class="cstat-no" title="statement not covered" > }</span>
1774
+ &nbsp;
1775
+ // Enhanced text wrapping that handles styled segments
1776
+ <span class="cstat-no" title="statement not covered" > const wrapStyledText = (segments: TextSegment[], fontSize: number, maxWidth: number): Array&lt;{segments: TextSegment[], width: number}&gt; =&gt; {</span>
1777
+ <span class="cstat-no" title="statement not covered" > const lines: Array&lt;{segments: TextSegment[], width: number}&gt; = [];</span>
1778
+ <span class="cstat-no" title="statement not covered" > let currentLine: TextSegment[] = [];</span>
1779
+ <span class="cstat-no" title="statement not covered" > let currentWidth = 0;</span>
1780
+ &nbsp;
1781
+ <span class="cstat-no" title="statement not covered" > for (let segmentIndex = 0; segmentIndex &lt; segments.length; segmentIndex++) {</span>
1782
+ <span class="cstat-no" title="statement not covered" > const segment = segments[segmentIndex];</span>
1783
+ <span class="cstat-no" title="statement not covered" > const words = segment.text.split(/\s+/).filter(word =&gt; word.length &gt; 0);</span>
1784
+
1785
+ <span class="cstat-no" title="statement not covered" > for (let i = 0; i &lt; words.length; i++) {</span>
1786
+ <span class="cstat-no" title="statement not covered" > const word = words[i];</span>
1787
+ <span class="cstat-no" title="statement not covered" > const wordWidth = segment.font.widthOfTextAtSize(word, fontSize);</span>
1788
+ <span class="cstat-no" title="statement not covered" > const spaceWidth = segment.font.widthOfTextAtSize(' ', fontSize);</span>
1789
+
1790
+ // Add space before word if:
1791
+ // 1. Not the first word in the line AND
1792
+ // 2. (Not the first word in the segment OR not the first segment)
1793
+ <span class="cstat-no" title="statement not covered" > const needSpace = currentLine.length &gt; 0 &amp;&amp; (i &gt; 0 || segmentIndex &gt; 0);</span>
1794
+ <span class="cstat-no" title="statement not covered" > const totalWidth = wordWidth + (needSpace ? spaceWidth : 0);</span>
1795
+ &nbsp;
1796
+ // Check if we need to wrap to new line
1797
+ <span class="cstat-no" title="statement not covered" > if (currentWidth + totalWidth &gt; maxWidth &amp;&amp; currentLine.length &gt; 0) {</span>
1798
+ // Finish current line
1799
+ <span class="cstat-no" title="statement not covered" > lines.push({ segments: [...currentLine], width: currentWidth });</span>
1800
+ <span class="cstat-no" title="statement not covered" > currentLine = [];</span>
1801
+ <span class="cstat-no" title="statement not covered" > currentWidth = 0;</span>
1802
+ <span class="cstat-no" title="statement not covered" > }</span>
1803
+ &nbsp;
1804
+ // Add the word to current line
1805
+ <span class="cstat-no" title="statement not covered" > if (needSpace &amp;&amp; currentLine.length &gt; 0) {</span>
1806
+ // Try to merge with last segment if same font and color
1807
+ <span class="cstat-no" title="statement not covered" > const lastSegment = currentLine[currentLine.length - 1];</span>
1808
+ <span class="cstat-no" title="statement not covered" > if (lastSegment.font === segment.font &amp;&amp; lastSegment.color === segment.color) {</span>
1809
+ <span class="cstat-no" title="statement not covered" > lastSegment.text += ' ' + word;</span>
1810
+ <span class="cstat-no" title="statement not covered" > currentWidth += spaceWidth + wordWidth;</span>
1811
+ <span class="cstat-no" title="statement not covered" > } else {</span>
1812
+ // Add space + word as new segment
1813
+ <span class="cstat-no" title="statement not covered" > currentLine.push({ text: ' ' + word, font: segment.font, color: segment.color });</span>
1814
+ <span class="cstat-no" title="statement not covered" > currentWidth += spaceWidth + wordWidth;</span>
1815
+ <span class="cstat-no" title="statement not covered" > }</span>
1816
+ <span class="cstat-no" title="statement not covered" > } else {</span>
1817
+ // Add word without space (first word in line or first word overall)
1818
+ <span class="cstat-no" title="statement not covered" > currentLine.push({ text: word, font: segment.font, color: segment.color });</span>
1819
+ <span class="cstat-no" title="statement not covered" > currentWidth += wordWidth;</span>
1820
+ <span class="cstat-no" title="statement not covered" > }</span>
1821
+ <span class="cstat-no" title="statement not covered" > }</span>
1822
+ <span class="cstat-no" title="statement not covered" > }</span>
1823
+ &nbsp;
1824
+ // Add final line if it has content
1825
+ <span class="cstat-no" title="statement not covered" > if (currentLine.length &gt; 0) {</span>
1826
+ <span class="cstat-no" title="statement not covered" > lines.push({ segments: currentLine, width: currentWidth });</span>
1827
+ <span class="cstat-no" title="statement not covered" > }</span>
1828
+ &nbsp;
1829
+ <span class="cstat-no" title="statement not covered" > return lines.length &gt; 0 ? lines : [{ segments: [{ text: '', font: defaultFont, color: rgb(0, 0, 0) }], width: 0 }];</span>
1830
+ <span class="cstat-no" title="statement not covered" > }</span>
1831
+ &nbsp;
1832
+ <span class="cstat-no" title="statement not covered" > let page = pdfDoc.addPage()</span>
1833
+ <span class="cstat-no" title="statement not covered" > let { width, height } = page.getSize()</span>
1834
+ <span class="cstat-no" title="statement not covered" > const { marginTop, marginBottom, marginLeft, marginRight } = { marginTop: 50, marginBottom: 50, marginLeft: 50, marginRight: 50 }</span>
1835
+ &nbsp;
1836
+ <span class="cstat-no" title="statement not covered" > const maxTextWidth = () =&gt; width - marginLeft - marginRight</span>
1837
+ &nbsp;
1838
+ <span class="cstat-no" title="statement not covered" > const wrapText = (text: string, font: any, fontSize: number, maxWidth: number): string[] =&gt; {</span>
1839
+ <span class="cstat-no" title="statement not covered" > if (!text) return ['']</span>
1840
+ <span class="cstat-no" title="statement not covered" > const words = text.split(/\s+/)</span>
1841
+ <span class="cstat-no" title="statement not covered" > const lines: string[] = []</span>
1842
+ <span class="cstat-no" title="statement not covered" > let current = ''</span>
1843
+ &nbsp;
1844
+ <span class="cstat-no" title="statement not covered" > const measure = (t: string) =&gt; font.widthOfTextAtSize(t, fontSize)</span>
1845
+ &nbsp;
1846
+ <span class="cstat-no" title="statement not covered" > const pushCurrent = () =&gt; {</span>
1847
+ <span class="cstat-no" title="statement not covered" > if (current.length &gt; 0) {</span>
1848
+ <span class="cstat-no" title="statement not covered" > lines.push(current)</span>
1849
+ <span class="cstat-no" title="statement not covered" > current = ''</span>
1850
+ <span class="cstat-no" title="statement not covered" > }</span>
1851
+ <span class="cstat-no" title="statement not covered" > }</span>
1852
+ &nbsp;
1853
+ <span class="cstat-no" title="statement not covered" > for (let i = 0; i &lt; words.length; i++) {</span>
1854
+ <span class="cstat-no" title="statement not covered" > const word = words[i]</span>
1855
+ <span class="cstat-no" title="statement not covered" > if (current.length === 0) {</span>
1856
+ // If a single word is too long, hard-break it
1857
+ <span class="cstat-no" title="statement not covered" > if (measure(word) &gt; maxWidth) {</span>
1858
+ <span class="cstat-no" title="statement not covered" > let chunk = ''</span>
1859
+ <span class="cstat-no" title="statement not covered" > for (const ch of word) {</span>
1860
+ <span class="cstat-no" title="statement not covered" > const test = chunk + ch</span>
1861
+ <span class="cstat-no" title="statement not covered" > if (measure(test) &gt; maxWidth &amp;&amp; chunk.length &gt; 0) {</span>
1862
+ <span class="cstat-no" title="statement not covered" > lines.push(chunk)</span>
1863
+ <span class="cstat-no" title="statement not covered" > chunk = ch</span>
1864
+ <span class="cstat-no" title="statement not covered" > } else {</span>
1865
+ <span class="cstat-no" title="statement not covered" > chunk = test</span>
1866
+ <span class="cstat-no" title="statement not covered" > }</span>
1867
+ <span class="cstat-no" title="statement not covered" > }</span>
1868
+ <span class="cstat-no" title="statement not covered" > current = chunk</span>
1869
+ <span class="cstat-no" title="statement not covered" > } else {</span>
1870
+ <span class="cstat-no" title="statement not covered" > current = word</span>
1871
+ <span class="cstat-no" title="statement not covered" > }</span>
1872
+ <span class="cstat-no" title="statement not covered" > } else {</span>
1873
+ <span class="cstat-no" title="statement not covered" > const test = current + ' ' + word</span>
1874
+ <span class="cstat-no" title="statement not covered" > if (measure(test) &lt;= maxWidth) {</span>
1875
+ <span class="cstat-no" title="statement not covered" > current = test</span>
1876
+ <span class="cstat-no" title="statement not covered" > } else {</span>
1877
+ <span class="cstat-no" title="statement not covered" > pushCurrent()</span>
1878
+ // start new line with this word; hard-break if needed
1879
+ <span class="cstat-no" title="statement not covered" > if (measure(word) &gt; maxWidth) {</span>
1880
+ <span class="cstat-no" title="statement not covered" > let chunk = ''</span>
1881
+ <span class="cstat-no" title="statement not covered" > for (const ch of word) {</span>
1882
+ <span class="cstat-no" title="statement not covered" > const t2 = chunk + ch</span>
1883
+ <span class="cstat-no" title="statement not covered" > if (measure(t2) &gt; maxWidth &amp;&amp; chunk.length &gt; 0) {</span>
1884
+ <span class="cstat-no" title="statement not covered" > lines.push(chunk)</span>
1885
+ <span class="cstat-no" title="statement not covered" > chunk = ch</span>
1886
+ <span class="cstat-no" title="statement not covered" > } else {</span>
1887
+ <span class="cstat-no" title="statement not covered" > chunk = t2</span>
1888
+ <span class="cstat-no" title="statement not covered" > }</span>
1889
+ <span class="cstat-no" title="statement not covered" > }</span>
1890
+ <span class="cstat-no" title="statement not covered" > current = chunk</span>
1891
+ <span class="cstat-no" title="statement not covered" > } else {</span>
1892
+ <span class="cstat-no" title="statement not covered" > current = word</span>
1893
+ <span class="cstat-no" title="statement not covered" > }</span>
1894
+ <span class="cstat-no" title="statement not covered" > }</span>
1895
+ <span class="cstat-no" title="statement not covered" > }</span>
1896
+ <span class="cstat-no" title="statement not covered" > }</span>
1897
+ <span class="cstat-no" title="statement not covered" > pushCurrent()</span>
1898
+ <span class="cstat-no" title="statement not covered" > return lines</span>
1899
+ <span class="cstat-no" title="statement not covered" > }</span>
1900
+ &nbsp;
1901
+ <span class="cstat-no" title="statement not covered" > let y = height - marginTop</span>
1902
+ <span class="cstat-no" title="statement not covered" > let lastLineHeight = -1</span>
1903
+ <span class="cstat-no" title="statement not covered" > logger.info(`createPdf: Starting to process ${blocks.length} blocks`);</span>
1904
+ <span class="cstat-no" title="statement not covered" > for (let i = 0; i &lt; blocks.length; i++) {</span>
1905
+ <span class="cstat-no" title="statement not covered" > const block = blocks[i];</span>
1906
+ <span class="cstat-no" title="statement not covered" > logger.info(`createPdf: Processing block ${i + 1}/${blocks.length}, format: ${block.format}, content type: ${typeof block.content}`);</span>
1907
+ <span class="cstat-no" title="statement not covered" > try {</span>
1908
+ <span class="cstat-no" title="statement not covered" > const preset = STYLE_PRESETS[block.format] || { fontSize: defaultFontSize, lineHeight: defaultLineHeight }</span>
1909
+ &nbsp;
1910
+ <span class="cstat-no" title="statement not covered" > const userLineHeight = (block as any).metadata?.lineHeight</span>
1911
+ &nbsp;
1912
+ <span class="cstat-no" title="statement not covered" > const fontSize = (block as any).metadata?.fontSize || preset.fontSize</span>
1913
+ <span class="cstat-no" title="statement not covered" > const lineHeight = (userLineHeight ? fontSize * userLineHeight : fontSize * preset.lineHeight)</span>
1914
+ <span class="cstat-no" title="statement not covered" > const paragraphSpacing = (block as any).metadata?.paragraphSpacing || defaultParagraphSpacing</span>
1915
+ <span class="cstat-no" title="statement not covered" > const indentWidth = (block as any).metadata?.indentWidth || defaultIndentWidth</span>
1916
+ &nbsp;
1917
+ <span class="cstat-no" title="statement not covered" > const paddingX = (block as any).metadata?.paddingX || defaultPadding</span>
1918
+ <span class="cstat-no" title="statement not covered" > const paddingY = (block as any).metadata?.paddingY || defaultPadding</span>
1919
+ &nbsp;
1920
+ <span class="cstat-no" title="statement not covered" > const font = FONTS[(block as any).metadata?.font] || preset.font || defaultFont // Broken</span>
1921
+ <span class="cstat-no" title="statement not covered" > const color = colorParse((block as any).metadata?.color || preset.color || rgb(0.0, 0.0, 0.0))</span>
1922
+ <span class="cstat-no" title="statement not covered" > const background = colorParse((block as any).metadata?.background || preset.background || rgb(1.0, 1.0, 1.0))</span>
1923
+ &nbsp;
1924
+ <span class="cstat-no" title="statement not covered" > if (lastLineHeight &gt;= 0) {</span>
1925
+ <span class="cstat-no" title="statement not covered" > y -= lineHeight - lastLineHeight</span>
1926
+ <span class="cstat-no" title="statement not covered" > } else {</span>
1927
+ <span class="cstat-no" title="statement not covered" > y -= fontSize</span>
1928
+ <span class="cstat-no" title="statement not covered" > }</span>
1929
+ &nbsp;
1930
+ <span class="cstat-no" title="statement not covered" > const ensureSpace = (needed: number) =&gt; {</span>
1931
+ <span class="cstat-no" title="statement not covered" > if (y - needed &lt; marginBottom) {</span>
1932
+ <span class="cstat-no" title="statement not covered" > page = pdfDoc.addPage()</span>
1933
+ <span class="cstat-no" title="statement not covered" > ; ({ width, height } = page.getSize())</span>
1934
+ <span class="cstat-no" title="statement not covered" > y = height - marginTop - fontSize</span>
1935
+ <span class="cstat-no" title="statement not covered" > lastLineHeight = -1</span>
1936
+ <span class="cstat-no" title="statement not covered" > return true</span>
1937
+ <span class="cstat-no" title="statement not covered" > } else { return false }</span>
1938
+ <span class="cstat-no" title="statement not covered" > }</span>
1939
+ &nbsp;
1940
+ <span class="cstat-no" title="statement not covered" > const drawParagraph = (text: string) =&gt; {</span>
1941
+ <span class="cstat-no" title="statement not covered" > const segments = parseMarkdown(text, font, color);</span>
1942
+ <span class="cstat-no" title="statement not covered" > const lines = wrapStyledText(segments, fontSize, maxTextWidth());</span>
1943
+
1944
+ <span class="cstat-no" title="statement not covered" > for (const line of lines) {</span>
1945
+ <span class="cstat-no" title="statement not covered" > ensureSpace(lineHeight);</span>
1946
+ <span class="cstat-no" title="statement not covered" > let currentX = marginLeft;</span>
1947
+
1948
+ <span class="cstat-no" title="statement not covered" > for (const segment of line.segments) {</span>
1949
+ <span class="cstat-no" title="statement not covered" > if (segment.text.trim()) {</span>
1950
+ <span class="cstat-no" title="statement not covered" > page.drawText(segment.text, {</span>
1951
+ <span class="cstat-no" title="statement not covered" > x: currentX,</span>
1952
+ <span class="cstat-no" title="statement not covered" > y: y,</span>
1953
+ <span class="cstat-no" title="statement not covered" > size: fontSize,</span>
1954
+ <span class="cstat-no" title="statement not covered" > font: segment.font,</span>
1955
+ <span class="cstat-no" title="statement not covered" > color: segment.color,</span>
1956
+ <span class="cstat-no" title="statement not covered" > });</span>
1957
+ <span class="cstat-no" title="statement not covered" > currentX += segment.font.widthOfTextAtSize(segment.text, fontSize);</span>
1958
+ <span class="cstat-no" title="statement not covered" > }</span>
1959
+ <span class="cstat-no" title="statement not covered" > }</span>
1960
+ <span class="cstat-no" title="statement not covered" > y -= lineHeight;</span>
1961
+ <span class="cstat-no" title="statement not covered" > }</span>
1962
+ <span class="cstat-no" title="statement not covered" > }</span>
1963
+ &nbsp;
1964
+ <span class="cstat-no" title="statement not covered" > const drawHeading = (text: string, align?: 'left' | 'center' | 'right') =&gt; {</span>
1965
+ <span class="cstat-no" title="statement not covered" > const segments = parseMarkdown(text, font, color);</span>
1966
+ <span class="cstat-no" title="statement not covered" > const lines = wrapStyledText(segments, fontSize, maxTextWidth());</span>
1967
+
1968
+ <span class="cstat-no" title="statement not covered" > for (const line of lines) {</span>
1969
+ <span class="cstat-no" title="statement not covered" > ensureSpace(lineHeight);</span>
1970
+ <span class="cstat-no" title="statement not covered" > let startX = marginLeft;</span>
1971
+
1972
+ <span class="cstat-no" title="statement not covered" > if (align === 'center') {</span>
1973
+ <span class="cstat-no" title="statement not covered" > startX = marginLeft + (maxTextWidth() - line.width) / 2;</span>
1974
+ <span class="cstat-no" title="statement not covered" > } else if (align === 'right') {</span>
1975
+ <span class="cstat-no" title="statement not covered" > startX = marginLeft + maxTextWidth() - line.width;</span>
1976
+ <span class="cstat-no" title="statement not covered" > }</span>
1977
+
1978
+ <span class="cstat-no" title="statement not covered" > let currentX = startX;</span>
1979
+ <span class="cstat-no" title="statement not covered" > for (const segment of line.segments) {</span>
1980
+ <span class="cstat-no" title="statement not covered" > if (segment.text.trim()) {</span>
1981
+ <span class="cstat-no" title="statement not covered" > page.drawText(segment.text, {</span>
1982
+ <span class="cstat-no" title="statement not covered" > x: currentX,</span>
1983
+ <span class="cstat-no" title="statement not covered" > y: y,</span>
1984
+ <span class="cstat-no" title="statement not covered" > size: fontSize,</span>
1985
+ <span class="cstat-no" title="statement not covered" > font: segment.font,</span>
1986
+ <span class="cstat-no" title="statement not covered" > color: segment.color,</span>
1987
+ <span class="cstat-no" title="statement not covered" > });</span>
1988
+ <span class="cstat-no" title="statement not covered" > currentX += segment.font.widthOfTextAtSize(segment.text, fontSize);</span>
1989
+ <span class="cstat-no" title="statement not covered" > }</span>
1990
+ <span class="cstat-no" title="statement not covered" > }</span>
1991
+ <span class="cstat-no" title="statement not covered" > y -= lineHeight;</span>
1992
+ <span class="cstat-no" title="statement not covered" > }</span>
1993
+ <span class="cstat-no" title="statement not covered" > }</span>
1994
+ &nbsp;
1995
+ <span class="cstat-no" title="statement not covered" > const drawBulletList = (items: string[]) =&gt; {</span>
1996
+ <span class="cstat-no" title="statement not covered" > const bulletIndent = indentWidth</span>
1997
+ <span class="cstat-no" title="statement not covered" > const gap = 8</span>
1998
+ <span class="cstat-no" title="statement not covered" > const contentWidth = maxTextWidth() - (bulletIndent + gap)</span>
1999
+ <span class="cstat-no" title="statement not covered" > for (const item of items) {</span>
2000
+ // Clean up any bullet symbols that the AI might have added
2001
+ <span class="cstat-no" title="statement not covered" > const cleanItem = item.replace(/^\s*[•*-]\s*/, '').trim();</span>
2002
+ <span class="cstat-no" title="statement not covered" > const segments = parseMarkdown(cleanItem, font, color);</span>
2003
+ <span class="cstat-no" title="statement not covered" > const lines = wrapStyledText(segments, fontSize, contentWidth);</span>
2004
+
2005
+ <span class="cstat-no" title="statement not covered" > for (let lineIndex = 0; lineIndex &lt; lines.length; lineIndex++) {</span>
2006
+ <span class="cstat-no" title="statement not covered" > const line = lines[lineIndex];</span>
2007
+ <span class="cstat-no" title="statement not covered" > ensureSpace(lineHeight);</span>
2008
+
2009
+ // Draw bullet only on first line
2010
+ <span class="cstat-no" title="statement not covered" > if (lineIndex === 0) {</span>
2011
+ <span class="cstat-no" title="statement not covered" > page.drawText('•', {</span>
2012
+ <span class="cstat-no" title="statement not covered" > x: marginLeft + gap,</span>
2013
+ <span class="cstat-no" title="statement not covered" > y: y,</span>
2014
+ <span class="cstat-no" title="statement not covered" > size: fontSize,</span>
2015
+ <span class="cstat-no" title="statement not covered" > font: font,</span>
2016
+ <span class="cstat-no" title="statement not covered" > color: color,</span>
2017
+ <span class="cstat-no" title="statement not covered" > });</span>
2018
+ <span class="cstat-no" title="statement not covered" > }</span>
2019
+
2020
+ // Draw styled text
2021
+ <span class="cstat-no" title="statement not covered" > let currentX = marginLeft + bulletIndent + gap;</span>
2022
+ <span class="cstat-no" title="statement not covered" > for (const segment of line.segments) {</span>
2023
+ <span class="cstat-no" title="statement not covered" > if (segment.text.trim()) {</span>
2024
+ <span class="cstat-no" title="statement not covered" > page.drawText(segment.text, {</span>
2025
+ <span class="cstat-no" title="statement not covered" > x: currentX,</span>
2026
+ <span class="cstat-no" title="statement not covered" > y: y,</span>
2027
+ <span class="cstat-no" title="statement not covered" > size: fontSize,</span>
2028
+ <span class="cstat-no" title="statement not covered" > font: segment.font,</span>
2029
+ <span class="cstat-no" title="statement not covered" > color: segment.color,</span>
2030
+ <span class="cstat-no" title="statement not covered" > });</span>
2031
+ <span class="cstat-no" title="statement not covered" > currentX += segment.font.widthOfTextAtSize(segment.text, fontSize);</span>
2032
+ <span class="cstat-no" title="statement not covered" > }</span>
2033
+ <span class="cstat-no" title="statement not covered" > }</span>
2034
+ <span class="cstat-no" title="statement not covered" > y -= lineHeight;</span>
2035
+ <span class="cstat-no" title="statement not covered" > }</span>
2036
+ <span class="cstat-no" title="statement not covered" > }</span>
2037
+ <span class="cstat-no" title="statement not covered" > }</span>
2038
+ &nbsp;
2039
+ <span class="cstat-no" title="statement not covered" > const drawNumberedList = (items: string[]) =&gt; {</span>
2040
+ <span class="cstat-no" title="statement not covered" > const numberIndent = indentWidth</span>
2041
+ <span class="cstat-no" title="statement not covered" > const gap = 8</span>
2042
+ <span class="cstat-no" title="statement not covered" > const contentWidth = maxTextWidth() - (numberIndent + gap)</span>
2043
+ <span class="cstat-no" title="statement not covered" > let index = 1</span>
2044
+ <span class="cstat-no" title="statement not covered" > for (const item of items) {</span>
2045
+ // Clean up any numbers that the AI might have added
2046
+ <span class="cstat-no" title="statement not covered" > const cleanItem = item.replace(/^\s*\d+\.\s*/, '').trim();</span>
2047
+ <span class="cstat-no" title="statement not covered" > const numLabel = `${index}.`</span>
2048
+ <span class="cstat-no" title="statement not covered" > const numWidth = font.widthOfTextAtSize(numLabel, fontSize)</span>
2049
+ <span class="cstat-no" title="statement not covered" > const segments = parseMarkdown(cleanItem, font, color);</span>
2050
+ <span class="cstat-no" title="statement not covered" > const lines = wrapStyledText(segments, fontSize, contentWidth);</span>
2051
+
2052
+ <span class="cstat-no" title="statement not covered" > for (let lineIndex = 0; lineIndex &lt; lines.length; lineIndex++) {</span>
2053
+ <span class="cstat-no" title="statement not covered" > const line = lines[lineIndex];</span>
2054
+ <span class="cstat-no" title="statement not covered" > ensureSpace(lineHeight);</span>
2055
+
2056
+ // Draw number only on first line
2057
+ <span class="cstat-no" title="statement not covered" > if (lineIndex === 0) {</span>
2058
+ <span class="cstat-no" title="statement not covered" > page.drawText(numLabel, {</span>
2059
+ <span class="cstat-no" title="statement not covered" > x: marginLeft + gap,</span>
2060
+ <span class="cstat-no" title="statement not covered" > y: y,</span>
2061
+ <span class="cstat-no" title="statement not covered" > size: fontSize,</span>
2062
+ <span class="cstat-no" title="statement not covered" > font: font,</span>
2063
+ <span class="cstat-no" title="statement not covered" > color: color,</span>
2064
+ <span class="cstat-no" title="statement not covered" > });</span>
2065
+ <span class="cstat-no" title="statement not covered" > }</span>
2066
+
2067
+ // Draw styled text
2068
+ <span class="cstat-no" title="statement not covered" > let currentX = marginLeft + Math.max(numberIndent, numWidth + 6) + gap;</span>
2069
+ <span class="cstat-no" title="statement not covered" > for (const segment of line.segments) {</span>
2070
+ <span class="cstat-no" title="statement not covered" > if (segment.text.trim()) {</span>
2071
+ <span class="cstat-no" title="statement not covered" > page.drawText(segment.text, {</span>
2072
+ <span class="cstat-no" title="statement not covered" > x: currentX,</span>
2073
+ <span class="cstat-no" title="statement not covered" > y: y,</span>
2074
+ <span class="cstat-no" title="statement not covered" > size: fontSize,</span>
2075
+ <span class="cstat-no" title="statement not covered" > font: segment.font,</span>
2076
+ <span class="cstat-no" title="statement not covered" > color: segment.color,</span>
2077
+ <span class="cstat-no" title="statement not covered" > });</span>
2078
+ <span class="cstat-no" title="statement not covered" > currentX += segment.font.widthOfTextAtSize(segment.text, fontSize);</span>
2079
+ <span class="cstat-no" title="statement not covered" > }</span>
2080
+ <span class="cstat-no" title="statement not covered" > }</span>
2081
+ <span class="cstat-no" title="statement not covered" > y -= lineHeight;</span>
2082
+ <span class="cstat-no" title="statement not covered" > }</span>
2083
+ <span class="cstat-no" title="statement not covered" > index++;</span>
2084
+ <span class="cstat-no" title="statement not covered" > }</span>
2085
+ <span class="cstat-no" title="statement not covered" > }</span>
2086
+ &nbsp;
2087
+ <span class="cstat-no" title="statement not covered" > const drawQuote = (text: string) =&gt; {</span>
2088
+ <span class="cstat-no" title="statement not covered" > const ruleWidth = 2</span>
2089
+ <span class="cstat-no" title="statement not covered" > const ruleGap = 8</span>
2090
+ <span class="cstat-no" title="statement not covered" > const contentX = marginLeft + ruleWidth + ruleGap</span>
2091
+ <span class="cstat-no" title="statement not covered" > const contentWidth = maxTextWidth() - (ruleWidth + ruleGap)</span>
2092
+ <span class="cstat-no" title="statement not covered" > const segments = parseMarkdown(text, font, color);</span>
2093
+ <span class="cstat-no" title="statement not covered" > const lines = wrapStyledText(segments, fontSize, contentWidth);</span>
2094
+ <span class="cstat-no" title="statement not covered" > const totalHeight = lines.length * lineHeight + fontSize</span>
2095
+ <span class="cstat-no" title="statement not covered" > var remainingHeight = totalHeight</span>
2096
+
2097
+ <span class="cstat-no" title="statement not covered" > for (const line of lines) {</span>
2098
+ <span class="cstat-no" title="statement not covered" > let pageAdded = ensureSpace(lineHeight)</span>
2099
+ <span class="cstat-no" title="statement not covered" > if (pageAdded || remainingHeight == totalHeight) {</span>
2100
+ <span class="cstat-no" title="statement not covered" > let blockHeight = Math.floor(Math.min(remainingHeight, y - marginBottom) / lineHeight) * lineHeight</span>
2101
+ <span class="cstat-no" title="statement not covered" > page.drawRectangle({</span>
2102
+ <span class="cstat-no" title="statement not covered" > x: marginLeft,</span>
2103
+ <span class="cstat-no" title="statement not covered" > y: y + lineHeight,</span>
2104
+ <span class="cstat-no" title="statement not covered" > width: ruleWidth,</span>
2105
+ <span class="cstat-no" title="statement not covered" > height: -blockHeight - lineHeight + fontSize,</span>
2106
+ <span class="cstat-no" title="statement not covered" > color: color,</span>
2107
+ <span class="cstat-no" title="statement not covered" > })</span>
2108
+ <span class="cstat-no" title="statement not covered" > remainingHeight -= blockHeight + lineHeight - fontSize</span>
2109
+ <span class="cstat-no" title="statement not covered" > }</span>
2110
+
2111
+ // Draw styled text
2112
+ <span class="cstat-no" title="statement not covered" > let currentX = contentX;</span>
2113
+ <span class="cstat-no" title="statement not covered" > for (const segment of line.segments) {</span>
2114
+ <span class="cstat-no" title="statement not covered" > if (segment.text.trim()) {</span>
2115
+ <span class="cstat-no" title="statement not covered" > page.drawText(segment.text, {</span>
2116
+ <span class="cstat-no" title="statement not covered" > x: currentX,</span>
2117
+ <span class="cstat-no" title="statement not covered" > y: y,</span>
2118
+ <span class="cstat-no" title="statement not covered" > size: fontSize,</span>
2119
+ <span class="cstat-no" title="statement not covered" > font: segment.font,</span>
2120
+ <span class="cstat-no" title="statement not covered" > color: segment.color,</span>
2121
+ <span class="cstat-no" title="statement not covered" > });</span>
2122
+ <span class="cstat-no" title="statement not covered" > currentX += segment.font.widthOfTextAtSize(segment.text, fontSize);</span>
2123
+ <span class="cstat-no" title="statement not covered" > }</span>
2124
+ <span class="cstat-no" title="statement not covered" > }</span>
2125
+ <span class="cstat-no" title="statement not covered" > y -= lineHeight;</span>
2126
+ <span class="cstat-no" title="statement not covered" > }</span>
2127
+ <span class="cstat-no" title="statement not covered" > y -= lineHeight - fontSize</span>
2128
+ <span class="cstat-no" title="statement not covered" > }</span>
2129
+ &nbsp;
2130
+ <span class="cstat-no" title="statement not covered" > const drawCodeBlock = (textLines: string[]) =&gt; {</span>
2131
+ <span class="cstat-no" title="statement not covered" > const codeFont = font</span>
2132
+
2133
+ // Detect indentation patterns
2134
+ <span class="cstat-no" title="statement not covered" > const detectIndentation = (lines: string[]) =&gt; {</span>
2135
+ <span class="cstat-no" title="statement not covered" > let tabCount = 0</span>
2136
+ <span class="cstat-no" title="statement not covered" > let spaceCount = 0</span>
2137
+ <span class="cstat-no" title="statement not covered" > let minSpaces = Infinity</span>
2138
+
2139
+ <span class="cstat-no" title="statement not covered" > for (const line of lines) {</span>
2140
+ <span class="cstat-no" title="statement not covered" > if (line.trim().length === 0) continue // Skip empty lines</span>
2141
+
2142
+ <span class="cstat-no" title="statement not covered" > const leadingWhitespace = line.match(/^(\s*)/)?.[1] || ''</span>
2143
+ <span class="cstat-no" title="statement not covered" > if (leadingWhitespace.includes('\t')) {</span>
2144
+ <span class="cstat-no" title="statement not covered" > tabCount++</span>
2145
+ <span class="cstat-no" title="statement not covered" > } else if (leadingWhitespace.length &gt; 0) {</span>
2146
+ <span class="cstat-no" title="statement not covered" > spaceCount++</span>
2147
+ <span class="cstat-no" title="statement not covered" > minSpaces = Math.min(minSpaces, leadingWhitespace.length)</span>
2148
+ <span class="cstat-no" title="statement not covered" > }</span>
2149
+ <span class="cstat-no" title="statement not covered" > }</span>
2150
+
2151
+ // Determine indentation strategy
2152
+ <span class="cstat-no" title="statement not covered" > if (tabCount &gt; spaceCount) {</span>
2153
+ <span class="cstat-no" title="statement not covered" > return { type: 'tab', width: indentWidth }</span>
2154
+ <span class="cstat-no" title="statement not covered" > } else if (spaceCount &gt; 0) {</span>
2155
+ // Use the most common space count, or default to 4
2156
+ <span class="cstat-no" title="statement not covered" > const commonSpaces = minSpaces === Infinity ? 4 : minSpaces</span>
2157
+ <span class="cstat-no" title="statement not covered" > return { type: 'space', width: commonSpaces * (fontSize * 0.6) } // Approximate space width</span>
2158
+ <span class="cstat-no" title="statement not covered" > } else {</span>
2159
+ <span class="cstat-no" title="statement not covered" > return { type: 'space', width: fontSize * 2.4 } // Default 4 spaces</span>
2160
+ <span class="cstat-no" title="statement not covered" > }</span>
2161
+ <span class="cstat-no" title="statement not covered" > }</span>
2162
+
2163
+ <span class="cstat-no" title="statement not covered" > const indentInfo = detectIndentation(textLines)</span>
2164
+
2165
+ // Process lines with indentation
2166
+ <span class="cstat-no" title="statement not covered" > const processedLines: { text: string; indentLevel: number; originalLine: string }[] = []</span>
2167
+
2168
+ <span class="cstat-no" title="statement not covered" > for (const line of textLines) {</span>
2169
+ <span class="cstat-no" title="statement not covered" > const leadingWhitespace = line.match(/^(\s*)/)?.[1] || ''</span>
2170
+ <span class="cstat-no" title="statement not covered" > let indentLevel = 0</span>
2171
+
2172
+ <span class="cstat-no" title="statement not covered" > if (indentInfo.type === 'tab') {</span>
2173
+ <span class="cstat-no" title="statement not covered" > indentLevel = leadingWhitespace.split('\t').length - 1</span>
2174
+ <span class="cstat-no" title="statement not covered" > } else {</span>
2175
+ // Count spaces, grouping by the detected space width
2176
+ <span class="cstat-no" title="statement not covered" > const spaceWidth = indentInfo.width / (fontSize * 0.6) // Convert back to space count</span>
2177
+ <span class="cstat-no" title="statement not covered" > indentLevel = Math.floor(leadingWhitespace.length / spaceWidth)</span>
2178
+ <span class="cstat-no" title="statement not covered" > }</span>
2179
+
2180
+ <span class="cstat-no" title="statement not covered" > processedLines.push({</span>
2181
+ <span class="cstat-no" title="statement not covered" > text: line.trim(),</span>
2182
+ <span class="cstat-no" title="statement not covered" > indentLevel,</span>
2183
+ <span class="cstat-no" title="statement not covered" > originalLine: line</span>
2184
+ <span class="cstat-no" title="statement not covered" > })</span>
2185
+ <span class="cstat-no" title="statement not covered" > }</span>
2186
+
2187
+ // Wrap each processed line separately to preserve line breaks and indentation
2188
+ <span class="cstat-no" title="statement not covered" > const wrappedLines: { text: string; indentLevel: number; isContinuation: boolean }[] = []</span>
2189
+ <span class="cstat-no" title="statement not covered" > const contentW = maxTextWidth() - paddingX * 2</span>
2190
+
2191
+ <span class="cstat-no" title="statement not covered" > for (const processedLine of processedLines) {</span>
2192
+ <span class="cstat-no" title="statement not covered" > if (processedLine.text.length === 0) {</span>
2193
+ // Empty line - preserve as empty line
2194
+ <span class="cstat-no" title="statement not covered" > wrappedLines.push({</span>
2195
+ <span class="cstat-no" title="statement not covered" > text: '',</span>
2196
+ <span class="cstat-no" title="statement not covered" > indentLevel: processedLine.indentLevel,</span>
2197
+ <span class="cstat-no" title="statement not covered" > isContinuation: false</span>
2198
+ <span class="cstat-no" title="statement not covered" > })</span>
2199
+ <span class="cstat-no" title="statement not covered" > } else {</span>
2200
+ <span class="cstat-no" title="statement not covered" > const parts = wrapText(processedLine.text, codeFont, fontSize, contentW)</span>
2201
+ <span class="cstat-no" title="statement not covered" > for (let i = 0; i &lt; parts.length; i++) {</span>
2202
+ <span class="cstat-no" title="statement not covered" > wrappedLines.push({</span>
2203
+ <span class="cstat-no" title="statement not covered" > text: parts[i],</span>
2204
+ <span class="cstat-no" title="statement not covered" > indentLevel: processedLine.indentLevel,</span>
2205
+ <span class="cstat-no" title="statement not covered" > isContinuation: i &gt; 0</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" > }</span>
2210
+
2211
+ <span class="cstat-no" title="statement not covered" > const totalHeight = wrappedLines.length * lineHeight + paddingY * 2</span>
2212
+ <span class="cstat-no" title="statement not covered" > var remainingHeight = totalHeight</span>
2213
+ <span class="cstat-no" title="statement not covered" > y -= paddingY</span>
2214
+
2215
+ <span class="cstat-no" title="statement not covered" > for (const wrappedLine of wrappedLines) {</span>
2216
+ <span class="cstat-no" title="statement not covered" > let pageAdded = ensureSpace(lineHeight + paddingY)</span>
2217
+ <span class="cstat-no" title="statement not covered" > if (pageAdded || remainingHeight == totalHeight) {</span>
2218
+ <span class="cstat-no" title="statement not covered" > let blockHeight = Math.floor(Math.min(remainingHeight, y - marginBottom - paddingY) / lineHeight) * lineHeight</span>
2219
+ <span class="cstat-no" title="statement not covered" > page.drawRectangle({</span>
2220
+ <span class="cstat-no" title="statement not covered" > x: marginLeft,</span>
2221
+ <span class="cstat-no" title="statement not covered" > y: y + fontSize,</span>
2222
+ <span class="cstat-no" title="statement not covered" > width: maxTextWidth(),</span>
2223
+ <span class="cstat-no" title="statement not covered" > height: -blockHeight - paddingY * 2,</span>
2224
+ <span class="cstat-no" title="statement not covered" > color: background,</span>
2225
+ <span class="cstat-no" title="statement not covered" > })</span>
2226
+ <span class="cstat-no" title="statement not covered" > remainingHeight -= blockHeight</span>
2227
+ <span class="cstat-no" title="statement not covered" > y -= paddingY</span>
2228
+ <span class="cstat-no" title="statement not covered" > }</span>
2229
+
2230
+ // Calculate indentation offset
2231
+ <span class="cstat-no" title="statement not covered" > const indentOffset = wrappedLine.indentLevel * indentInfo.width</span>
2232
+
2233
+ <span class="cstat-no" title="statement not covered" > page.drawText(wrappedLine.text, {</span>
2234
+ <span class="cstat-no" title="statement not covered" > x: marginLeft + paddingX + indentOffset,</span>
2235
+ <span class="cstat-no" title="statement not covered" > y: y,</span>
2236
+ <span class="cstat-no" title="statement not covered" > size: fontSize,</span>
2237
+ <span class="cstat-no" title="statement not covered" > font: codeFont,</span>
2238
+ <span class="cstat-no" title="statement not covered" > color: color,</span>
2239
+ <span class="cstat-no" title="statement not covered" > })</span>
2240
+ <span class="cstat-no" title="statement not covered" > y -= lineHeight</span>
2241
+ <span class="cstat-no" title="statement not covered" > }</span>
2242
+ <span class="cstat-no" title="statement not covered" > y -= paddingY</span>
2243
+ <span class="cstat-no" title="statement not covered" > }</span>
2244
+ &nbsp;
2245
+ // Render by block format
2246
+ <span class="cstat-no" title="statement not covered" > switch (block.format) {</span>
2247
+ <span class="cstat-no" title="statement not covered" > case FormatTypes.HEADER_1:</span>
2248
+ <span class="cstat-no" title="statement not covered" > case FormatTypes.HEADER_2:</span>
2249
+ <span class="cstat-no" title="statement not covered" > case FormatTypes.HEADER_3:</span>
2250
+ <span class="cstat-no" title="statement not covered" > case FormatTypes.HEADER_4:</span>
2251
+ <span class="cstat-no" title="statement not covered" > case FormatTypes.HEADER_5:</span>
2252
+ <span class="cstat-no" title="statement not covered" > case FormatTypes.HEADER_6: {</span>
2253
+ <span class="cstat-no" title="statement not covered" > const align = (block as any).metadata?.align as 'left' | 'center' | 'right' | undefined</span>
2254
+ <span class="cstat-no" title="statement not covered" > drawHeading(String(block.content), align)</span>
2255
+ <span class="cstat-no" title="statement not covered" > break</span>
2256
+ <span class="cstat-no" title="statement not covered" > }</span>
2257
+ <span class="cstat-no" title="statement not covered" > case FormatTypes.BULLET: {</span>
2258
+ <span class="cstat-no" title="statement not covered" > const items = Array.isArray(block.content) ? block.content.map(String) : [String(block.content)]</span>
2259
+ <span class="cstat-no" title="statement not covered" > drawBulletList(items)</span>
2260
+ <span class="cstat-no" title="statement not covered" > break</span>
2261
+ <span class="cstat-no" title="statement not covered" > }</span>
2262
+ <span class="cstat-no" title="statement not covered" > case FormatTypes.NUMBERED: {</span>
2263
+ <span class="cstat-no" title="statement not covered" > const items = Array.isArray(block.content) ? block.content.map(String) : [String(block.content)]</span>
2264
+ <span class="cstat-no" title="statement not covered" > drawNumberedList(items)</span>
2265
+ <span class="cstat-no" title="statement not covered" > break</span>
2266
+ <span class="cstat-no" title="statement not covered" > }</span>
2267
+ <span class="cstat-no" title="statement not covered" > case FormatTypes.QUOTE: {</span>
2268
+ <span class="cstat-no" title="statement not covered" > drawQuote(String(block.content))</span>
2269
+ <span class="cstat-no" title="statement not covered" > break</span>
2270
+ <span class="cstat-no" title="statement not covered" > }</span>
2271
+ <span class="cstat-no" title="statement not covered" > case FormatTypes.CODE_BLOCK: {</span>
2272
+ <span class="cstat-no" title="statement not covered" > const lines = Array.isArray(block.content) ? block.content.map(String) : String(block.content).split('\n')</span>
2273
+ <span class="cstat-no" title="statement not covered" > drawCodeBlock(lines)</span>
2274
+ <span class="cstat-no" title="statement not covered" > break</span>
2275
+ <span class="cstat-no" title="statement not covered" > }</span>
2276
+ <span class="cstat-no" title="statement not covered" > default: {</span>
2277
+ <span class="cstat-no" title="statement not covered" > if (typeof block.content === 'string') {</span>
2278
+ <span class="cstat-no" title="statement not covered" > drawParagraph(block.content)</span>
2279
+ <span class="cstat-no" title="statement not covered" > } else {</span>
2280
+ <span class="cstat-no" title="statement not covered" > for (const c of block.content) {</span>
2281
+ <span class="cstat-no" title="statement not covered" > drawParagraph(String(c))</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" > }</span>
2286
+ <span class="cstat-no" title="statement not covered" > logger.info(`createPdf: Successfully processed block ${i + 1}`);</span>
2287
+ <span class="cstat-no" title="statement not covered" > y -= paragraphSpacing</span>
2288
+ <span class="cstat-no" title="statement not covered" > lastLineHeight = lineHeight</span>
2289
+ <span class="cstat-no" title="statement not covered" > } catch (blockError) {</span>
2290
+ <span class="cstat-no" title="statement not covered" > logger.error(`createPdf: Error processing block ${i + 1}: ${blockError}`);</span>
2291
+ <span class="cstat-no" title="statement not covered" > throw blockError;</span>
2292
+ <span class="cstat-no" title="statement not covered" > }</span>
2293
+ <span class="cstat-no" title="statement not covered" > }</span>
2294
+ &nbsp;
2295
+ <span class="cstat-no" title="statement not covered" > logger.info('createPdf: About to save PDF document');</span>
2296
+ <span class="cstat-no" title="statement not covered" > const pdfBytes = await pdfDoc.save()</span>
2297
+ <span class="cstat-no" title="statement not covered" > logger.info(`createPdf: PDF saved successfully, bytes length: ${pdfBytes.length}`);</span>
2298
+ <span class="cstat-no" title="statement not covered" > return pdfBytes</span>
2299
+ <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
2300
+ <span class="cstat-no" title="statement not covered" > logger.error(`createPdf: Error during PDF creation: ${error}`);</span>
2301
+ <span class="cstat-no" title="statement not covered" > throw error;</span>
2302
+ <span class="cstat-no" title="statement not covered" > }</span>
2303
+ <span class="cstat-no" title="statement not covered" >}</span>
2304
+ &nbsp;</pre></td></tr></table></pre>
2305
+
2306
+ <div class='push'></div><!-- for sticky footer -->
2307
+ </div><!-- /wrapper -->
2308
+ <div class='footer quiet pad2 space-top1 center small'>
2309
+ Code coverage generated by
2310
+ <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
2311
+ at 2025-11-22T10:42:40.796Z
2312
+ </div>
2313
+ <script src="../../../prettify.js"></script>
2314
+ <script>
2315
+ window.onload = function () {
2316
+ prettyPrint();
2317
+ };
2318
+ </script>
2319
+ <script src="../../../sorter.js"></script>
2320
+ <script src="../../../block-navigation.js"></script>
2321
+ </body>
2322
+ </html>
2323
+