@studious-lms/server 1.2.45 → 1.2.47
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.
- package/.env.example +45 -0
- package/.env.test.example +37 -0
- package/README.md +34 -7
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/clover.xml +12110 -0
- package/coverage/coverage-final.json +44 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +221 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/server/index.html +116 -0
- package/coverage/server/src/exportType.ts.html +109 -0
- package/coverage/server/src/index.html +161 -0
- package/coverage/server/src/index.ts.html +1702 -0
- package/coverage/server/src/instrument.ts.html +130 -0
- package/coverage/server/src/lib/config/env.ts.html +448 -0
- package/coverage/server/src/lib/config/index.html +116 -0
- package/coverage/server/src/lib/fileUpload.ts.html +1138 -0
- package/coverage/server/src/lib/googleCloudStorage.ts.html +334 -0
- package/coverage/server/src/lib/index.html +206 -0
- package/coverage/server/src/lib/jsonConversion.ts.html +2323 -0
- package/coverage/server/src/lib/jsonStyles.ts.html +193 -0
- package/coverage/server/src/lib/notificationHandler.ts.html +193 -0
- package/coverage/server/src/lib/pusher.ts.html +121 -0
- package/coverage/server/src/lib/thumbnailGenerator.ts.html +592 -0
- package/coverage/server/src/middleware/auth.ts.html +646 -0
- package/coverage/server/src/middleware/index.html +146 -0
- package/coverage/server/src/middleware/logging.ts.html +244 -0
- package/coverage/server/src/middleware/security.ts.html +271 -0
- package/coverage/server/src/routers/_app.ts.html +232 -0
- package/coverage/server/src/routers/agenda.ts.html +319 -0
- package/coverage/server/src/routers/announcement.ts.html +3481 -0
- package/coverage/server/src/routers/assignment.ts.html +7633 -0
- package/coverage/server/src/routers/attendance.ts.html +1030 -0
- package/coverage/server/src/routers/auth.ts.html +1081 -0
- package/coverage/server/src/routers/class.ts.html +3535 -0
- package/coverage/server/src/routers/comment.ts.html +991 -0
- package/coverage/server/src/routers/conversation.ts.html +982 -0
- package/coverage/server/src/routers/event.ts.html +1609 -0
- package/coverage/server/src/routers/file.ts.html +1144 -0
- package/coverage/server/src/routers/folder.ts.html +2797 -0
- package/coverage/server/src/routers/index.html +386 -0
- package/coverage/server/src/routers/labChat.ts.html +3073 -0
- package/coverage/server/src/routers/marketing.ts.html +340 -0
- package/coverage/server/src/routers/message.ts.html +1912 -0
- package/coverage/server/src/routers/notifications.ts.html +364 -0
- package/coverage/server/src/routers/section.ts.html +1120 -0
- package/coverage/server/src/routers/user.ts.html +862 -0
- package/coverage/server/src/routers/worksheet.ts.html +1729 -0
- package/coverage/server/src/trpc.ts.html +397 -0
- package/coverage/server/src/types/index.html +116 -0
- package/coverage/server/src/types/trpc.ts.html +127 -0
- package/coverage/server/src/utils/aiUser.ts.html +280 -0
- package/coverage/server/src/utils/email.ts.html +121 -0
- package/coverage/server/src/utils/generateInviteCode.ts.html +106 -0
- package/coverage/server/src/utils/index.html +206 -0
- package/coverage/server/src/utils/inference.ts.html +709 -0
- package/coverage/server/src/utils/logger.ts.html +664 -0
- package/coverage/server/src/utils/prismaErrorHandler.ts.html +907 -0
- package/coverage/server/src/utils/prismaWrapper.ts.html +355 -0
- package/coverage/server/vitest.config.ts.html +196 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +83 -52
- package/dist/index.js.map +1 -1
- package/dist/instrument.js +15 -8
- package/dist/instrument.js.map +1 -1
- package/dist/lib/config/env.d.ts +169 -0
- package/dist/lib/config/env.d.ts.map +1 -0
- package/dist/lib/config/env.js +115 -0
- package/dist/lib/config/env.js.map +1 -0
- package/dist/lib/fileUpload.d.ts.map +1 -1
- package/dist/lib/fileUpload.js +5 -4
- package/dist/lib/fileUpload.js.map +1 -1
- package/dist/lib/googleCloudStorage.d.ts.map +1 -1
- package/dist/lib/googleCloudStorage.js +7 -8
- package/dist/lib/googleCloudStorage.js.map +1 -1
- package/dist/lib/jsonConversion.d.ts.map +1 -1
- package/dist/lib/jsonConversion.js +14 -16
- package/dist/lib/jsonConversion.js.map +1 -1
- package/dist/lib/notificationHandler.d.ts +2 -2
- package/dist/lib/prisma.d.ts +2 -2
- package/dist/lib/prisma.d.ts.map +1 -1
- package/dist/lib/prisma.js +22 -3
- package/dist/lib/prisma.js.map +1 -1
- package/dist/lib/pusher.d.ts.map +1 -1
- package/dist/lib/pusher.js +8 -7
- package/dist/lib/pusher.js.map +1 -1
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +7 -5
- package/dist/middleware/auth.js.map +1 -1
- package/dist/middleware/security.d.ts +5 -0
- package/dist/middleware/security.d.ts.map +1 -0
- package/dist/middleware/security.js +77 -0
- package/dist/middleware/security.js.map +1 -0
- package/dist/routers/_app.d.ts +368 -108
- package/dist/routers/_app.d.ts.map +1 -1
- package/dist/routers/_app.js +4 -2
- package/dist/routers/_app.js.map +1 -1
- package/dist/routers/agenda.d.ts.map +1 -1
- package/dist/routers/agenda.js +12 -9
- package/dist/routers/agenda.js.map +1 -1
- package/dist/routers/announcement.d.ts +8 -0
- package/dist/routers/announcement.d.ts.map +1 -1
- package/dist/routers/announcement.js +6 -4
- package/dist/routers/announcement.js.map +1 -1
- package/dist/routers/assignment.d.ts +17 -4
- package/dist/routers/assignment.d.ts.map +1 -1
- package/dist/routers/assignment.js +51 -19
- package/dist/routers/assignment.js.map +1 -1
- package/dist/routers/attendance.d.ts +1 -0
- package/dist/routers/attendance.d.ts.map +1 -1
- package/dist/routers/attendance.js +4 -4
- package/dist/routers/attendance.js.map +1 -1
- package/dist/routers/auth.d.ts +20 -0
- package/dist/routers/auth.d.ts.map +1 -1
- package/dist/routers/auth.js +132 -15
- package/dist/routers/auth.js.map +1 -1
- package/dist/routers/class.d.ts +10 -0
- package/dist/routers/class.d.ts.map +1 -1
- package/dist/routers/class.js +49 -5
- package/dist/routers/class.js.map +1 -1
- package/dist/routers/comment.d.ts +2 -0
- package/dist/routers/comment.d.ts.map +1 -1
- package/dist/routers/conversation.d.ts +2 -0
- package/dist/routers/conversation.d.ts.map +1 -1
- package/dist/routers/conversation.js +46 -31
- package/dist/routers/conversation.js.map +1 -1
- package/dist/routers/file.d.ts.map +1 -1
- package/dist/routers/file.js +30 -7
- package/dist/routers/file.js.map +1 -1
- package/dist/routers/labChat.d.ts +2 -0
- package/dist/routers/labChat.d.ts.map +1 -1
- package/dist/routers/labChat.js +5 -322
- package/dist/routers/labChat.js.map +1 -1
- package/dist/routers/marketing.d.ts +1 -1
- package/dist/routers/message.d.ts +1 -0
- package/dist/routers/message.d.ts.map +1 -1
- package/dist/routers/message.js +3 -2
- package/dist/routers/message.js.map +1 -1
- package/dist/routers/newtonChat.d.ts +55 -0
- package/dist/routers/newtonChat.d.ts.map +1 -0
- package/dist/routers/newtonChat.js +262 -0
- package/dist/routers/newtonChat.js.map +1 -0
- package/dist/routers/notifications.d.ts +4 -4
- package/dist/routers/section.d.ts +19 -4
- package/dist/routers/section.d.ts.map +1 -1
- package/dist/routers/section.js +26 -8
- package/dist/routers/section.js.map +1 -1
- package/dist/routers/user.d.ts.map +1 -1
- package/dist/routers/user.js +5 -4
- package/dist/routers/user.js.map +1 -1
- package/dist/routers/worksheet.d.ts +44 -41
- package/dist/routers/worksheet.d.ts.map +1 -1
- package/dist/routers/worksheet.js +25 -34
- package/dist/routers/worksheet.js.map +1 -1
- package/dist/seedDatabase.d.ts +1 -1
- package/dist/seedDatabase.js +275 -284
- package/dist/seedDatabase.js.map +1 -1
- package/dist/server/pipelines/aiLabChat.d.ts +21 -0
- package/dist/server/pipelines/aiLabChat.d.ts.map +1 -0
- package/dist/server/pipelines/aiLabChat.js +456 -0
- package/dist/server/pipelines/aiLabChat.js.map +1 -0
- package/dist/server/pipelines/aiNewtonChat.d.ts +30 -0
- package/dist/server/pipelines/aiNewtonChat.d.ts.map +1 -0
- package/dist/server/pipelines/aiNewtonChat.js +280 -0
- package/dist/server/pipelines/aiNewtonChat.js.map +1 -0
- package/dist/server/pipelines/gradeWorksheet.d.ts +15 -0
- package/dist/server/pipelines/gradeWorksheet.d.ts.map +1 -0
- package/dist/server/pipelines/gradeWorksheet.js +139 -0
- package/dist/server/pipelines/gradeWorksheet.js.map +1 -0
- package/dist/trpc.d.ts.map +1 -1
- package/dist/trpc.js +2 -2
- package/dist/trpc.js.map +1 -1
- package/dist/utils/email.d.ts +9 -1
- package/dist/utils/email.d.ts.map +1 -1
- package/dist/utils/email.js +20 -5
- package/dist/utils/email.js.map +1 -1
- package/dist/utils/inference.d.ts +5 -0
- package/dist/utils/inference.d.ts.map +1 -1
- package/dist/utils/inference.js +71 -7
- package/dist/utils/inference.js.map +1 -1
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +3 -3
- package/dist/utils/logger.js.map +1 -1
- package/docker-compose.yml +14 -0
- package/package.json +13 -4
- package/prisma/schema.prisma +34 -5
- package/scripts/test-pre-push.ts +14 -0
- package/src/index.ts +98 -54
- package/src/instrument.ts +13 -6
- package/src/lib/config/env.ts +126 -0
- package/src/lib/fileUpload.ts +3 -2
- package/src/lib/googleCloudStorage.ts +6 -6
- package/src/lib/jsonConversion.ts +12 -14
- package/src/lib/prisma.ts +23 -2
- package/src/lib/pusher.ts +6 -5
- package/src/middleware/auth.ts +5 -3
- package/src/middleware/security.ts +80 -0
- package/src/routers/_app.ts +2 -0
- package/src/routers/agenda.ts +10 -7
- package/src/routers/announcement.ts +4 -2
- package/src/routers/assignment.ts +74 -41
- package/src/routers/attendance.ts +2 -2
- package/src/routers/auth.ts +143 -14
- package/src/routers/class.ts +52 -3
- package/src/routers/conversation.ts +49 -29
- package/src/routers/file.ts +29 -5
- package/src/routers/labChat.ts +3 -367
- package/src/routers/message.ts +1 -1
- package/src/routers/newtonChat.ts +299 -0
- package/src/routers/section.ts +26 -6
- package/src/routers/user.ts +3 -2
- package/src/routers/worksheet.ts +26 -38
- package/src/seedDatabase.ts +290 -283
- package/src/server/pipelines/aiLabChat.ts +507 -0
- package/src/server/pipelines/aiNewtonChat.ts +338 -0
- package/src/server/pipelines/gradeWorksheet.ts +151 -0
- package/src/trpc.ts +2 -0
- package/src/utils/email.ts +30 -3
- package/src/utils/inference.ts +85 -5
- package/src/utils/logger.ts +2 -1
- package/tests/announcement.test.ts +164 -0
- package/tests/assignment.test.ts +296 -0
- package/tests/attendance.test.ts +168 -0
- package/tests/auth.test.ts +33 -10
- package/tests/class.test.ts +34 -9
- package/tests/event.test.ts +228 -0
- package/tests/section.test.ts +216 -0
- package/tests/setup.ts +70 -16
- package/tests/user.test.ts +158 -0
- package/vitest.config.ts +26 -0
- package/API_SPECIFICATION.md +0 -1597
- package/BASE64_REMOVAL_SUMMARY.md +0 -164
- package/CHAT_API_SPEC.md +0 -579
- package/LAB_CHAT_API_SPEC.md +0 -518
- package/dist/routers/school.d.ts +0 -208
- package/dist/routers/school.d.ts.map +0 -1
- package/dist/routers/school.js +0 -483
|
@@ -0,0 +1,1702 @@
|
|
|
1
|
+
|
|
2
|
+
<!doctype html>
|
|
3
|
+
<html lang="en">
|
|
4
|
+
|
|
5
|
+
<head>
|
|
6
|
+
<title>Code coverage report for server/src/index.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</a> index.ts</h1>
|
|
23
|
+
<div class='clearfix'>
|
|
24
|
+
|
|
25
|
+
<div class='fl pad1y space-right2'>
|
|
26
|
+
<span class="strong">0% </span>
|
|
27
|
+
<span class="quiet">Statements</span>
|
|
28
|
+
<span class='fraction'>0/413</span>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
<div class='fl pad1y space-right2'>
|
|
33
|
+
<span class="strong">0% </span>
|
|
34
|
+
<span class="quiet">Branches</span>
|
|
35
|
+
<span class='fraction'>0/1</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% </span>
|
|
48
|
+
<span class="quiet">Lines</span>
|
|
49
|
+
<span class='fraction'>0/413</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></td><td class="line-coverage quiet"><span class="cline-any cline-no"> </span>
|
|
606
|
+
<span class="cline-any cline-neutral"> </span>
|
|
607
|
+
<span class="cline-any cline-no"> </span>
|
|
608
|
+
<span class="cline-any cline-no"> </span>
|
|
609
|
+
<span class="cline-any cline-no"> </span>
|
|
610
|
+
<span class="cline-any cline-neutral"> </span>
|
|
611
|
+
<span class="cline-any cline-no"> </span>
|
|
612
|
+
<span class="cline-any cline-no"> </span>
|
|
613
|
+
<span class="cline-any cline-no"> </span>
|
|
614
|
+
<span class="cline-any cline-no"> </span>
|
|
615
|
+
<span class="cline-any cline-no"> </span>
|
|
616
|
+
<span class="cline-any cline-no"> </span>
|
|
617
|
+
<span class="cline-any cline-no"> </span>
|
|
618
|
+
<span class="cline-any cline-neutral"> </span>
|
|
619
|
+
<span class="cline-any cline-no"> </span>
|
|
620
|
+
<span class="cline-any cline-neutral"> </span>
|
|
621
|
+
<span class="cline-any cline-no"> </span>
|
|
622
|
+
<span class="cline-any cline-no"> </span>
|
|
623
|
+
<span class="cline-any cline-no"> </span>
|
|
624
|
+
<span class="cline-any cline-no"> </span>
|
|
625
|
+
<span class="cline-any cline-neutral"> </span>
|
|
626
|
+
<span class="cline-any cline-neutral"> </span>
|
|
627
|
+
<span class="cline-any cline-no"> </span>
|
|
628
|
+
<span class="cline-any cline-neutral"> </span>
|
|
629
|
+
<span class="cline-any cline-no"> </span>
|
|
630
|
+
<span class="cline-any cline-neutral"> </span>
|
|
631
|
+
<span class="cline-any cline-no"> </span>
|
|
632
|
+
<span class="cline-any cline-no"> </span>
|
|
633
|
+
<span class="cline-any cline-neutral"> </span>
|
|
634
|
+
<span class="cline-any cline-no"> </span>
|
|
635
|
+
<span class="cline-any cline-no"> </span>
|
|
636
|
+
<span class="cline-any cline-no"> </span>
|
|
637
|
+
<span class="cline-any cline-no"> </span>
|
|
638
|
+
<span class="cline-any cline-no"> </span>
|
|
639
|
+
<span class="cline-any cline-neutral"> </span>
|
|
640
|
+
<span class="cline-any cline-no"> </span>
|
|
641
|
+
<span class="cline-any cline-neutral"> </span>
|
|
642
|
+
<span class="cline-any cline-no"> </span>
|
|
643
|
+
<span class="cline-any cline-no"> </span>
|
|
644
|
+
<span class="cline-any cline-no"> </span>
|
|
645
|
+
<span class="cline-any cline-no"> </span>
|
|
646
|
+
<span class="cline-any cline-no"> </span>
|
|
647
|
+
<span class="cline-any cline-no"> </span>
|
|
648
|
+
<span class="cline-any cline-neutral"> </span>
|
|
649
|
+
<span class="cline-any cline-no"> </span>
|
|
650
|
+
<span class="cline-any cline-no"> </span>
|
|
651
|
+
<span class="cline-any cline-no"> </span>
|
|
652
|
+
<span class="cline-any cline-no"> </span>
|
|
653
|
+
<span class="cline-any cline-no"> </span>
|
|
654
|
+
<span class="cline-any cline-no"> </span>
|
|
655
|
+
<span class="cline-any cline-neutral"> </span>
|
|
656
|
+
<span class="cline-any cline-no"> </span>
|
|
657
|
+
<span class="cline-any cline-no"> </span>
|
|
658
|
+
<span class="cline-any cline-neutral"> </span>
|
|
659
|
+
<span class="cline-any cline-neutral"> </span>
|
|
660
|
+
<span class="cline-any cline-no"> </span>
|
|
661
|
+
<span class="cline-any cline-no"> </span>
|
|
662
|
+
<span class="cline-any cline-no"> </span>
|
|
663
|
+
<span class="cline-any cline-no"> </span>
|
|
664
|
+
<span class="cline-any cline-no"> </span>
|
|
665
|
+
<span class="cline-any cline-no"> </span>
|
|
666
|
+
<span class="cline-any cline-no"> </span>
|
|
667
|
+
<span class="cline-any cline-neutral"> </span>
|
|
668
|
+
<span class="cline-any cline-neutral"> </span>
|
|
669
|
+
<span class="cline-any cline-no"> </span>
|
|
670
|
+
<span class="cline-any cline-no"> </span>
|
|
671
|
+
<span class="cline-any cline-no"> </span>
|
|
672
|
+
<span class="cline-any cline-no"> </span>
|
|
673
|
+
<span class="cline-any cline-no"> </span>
|
|
674
|
+
<span class="cline-any cline-no"> </span>
|
|
675
|
+
<span class="cline-any cline-no"> </span>
|
|
676
|
+
<span class="cline-any cline-neutral"> </span>
|
|
677
|
+
<span class="cline-any cline-no"> </span>
|
|
678
|
+
<span class="cline-any cline-no"> </span>
|
|
679
|
+
<span class="cline-any cline-no"> </span>
|
|
680
|
+
<span class="cline-any cline-no"> </span>
|
|
681
|
+
<span class="cline-any cline-no"> </span>
|
|
682
|
+
<span class="cline-any cline-neutral"> </span>
|
|
683
|
+
<span class="cline-any cline-neutral"> </span>
|
|
684
|
+
<span class="cline-any cline-no"> </span>
|
|
685
|
+
<span class="cline-any cline-no"> </span>
|
|
686
|
+
<span class="cline-any cline-no"> </span>
|
|
687
|
+
<span class="cline-any cline-no"> </span>
|
|
688
|
+
<span class="cline-any cline-no"> </span>
|
|
689
|
+
<span class="cline-any cline-no"> </span>
|
|
690
|
+
<span class="cline-any cline-no"> </span>
|
|
691
|
+
<span class="cline-any cline-no"> </span>
|
|
692
|
+
<span class="cline-any cline-no"> </span>
|
|
693
|
+
<span class="cline-any cline-no"> </span>
|
|
694
|
+
<span class="cline-any cline-no"> </span>
|
|
695
|
+
<span class="cline-any cline-neutral"> </span>
|
|
696
|
+
<span class="cline-any cline-neutral"> </span>
|
|
697
|
+
<span class="cline-any cline-no"> </span>
|
|
698
|
+
<span class="cline-any cline-no"> </span>
|
|
699
|
+
<span class="cline-any cline-no"> </span>
|
|
700
|
+
<span class="cline-any cline-no"> </span>
|
|
701
|
+
<span class="cline-any cline-no"> </span>
|
|
702
|
+
<span class="cline-any cline-no"> </span>
|
|
703
|
+
<span class="cline-any cline-no"> </span>
|
|
704
|
+
<span class="cline-any cline-no"> </span>
|
|
705
|
+
<span class="cline-any cline-no"> </span>
|
|
706
|
+
<span class="cline-any cline-no"> </span>
|
|
707
|
+
<span class="cline-any cline-no"> </span>
|
|
708
|
+
<span class="cline-any cline-no"> </span>
|
|
709
|
+
<span class="cline-any cline-no"> </span>
|
|
710
|
+
<span class="cline-any cline-neutral"> </span>
|
|
711
|
+
<span class="cline-any cline-no"> </span>
|
|
712
|
+
<span class="cline-any cline-no"> </span>
|
|
713
|
+
<span class="cline-any cline-no"> </span>
|
|
714
|
+
<span class="cline-any cline-no"> </span>
|
|
715
|
+
<span class="cline-any cline-neutral"> </span>
|
|
716
|
+
<span class="cline-any cline-neutral"> </span>
|
|
717
|
+
<span class="cline-any cline-no"> </span>
|
|
718
|
+
<span class="cline-any cline-neutral"> </span>
|
|
719
|
+
<span class="cline-any cline-no"> </span>
|
|
720
|
+
<span class="cline-any cline-no"> </span>
|
|
721
|
+
<span class="cline-any cline-no"> </span>
|
|
722
|
+
<span class="cline-any cline-no"> </span>
|
|
723
|
+
<span class="cline-any cline-no"> </span>
|
|
724
|
+
<span class="cline-any cline-no"> </span>
|
|
725
|
+
<span class="cline-any cline-no"> </span>
|
|
726
|
+
<span class="cline-any cline-no"> </span>
|
|
727
|
+
<span class="cline-any cline-no"> </span>
|
|
728
|
+
<span class="cline-any cline-no"> </span>
|
|
729
|
+
<span class="cline-any cline-no"> </span>
|
|
730
|
+
<span class="cline-any cline-neutral"> </span>
|
|
731
|
+
<span class="cline-any cline-neutral"> </span>
|
|
732
|
+
<span class="cline-any cline-neutral"> </span>
|
|
733
|
+
<span class="cline-any cline-no"> </span>
|
|
734
|
+
<span class="cline-any cline-neutral"> </span>
|
|
735
|
+
<span class="cline-any cline-no"> </span>
|
|
736
|
+
<span class="cline-any cline-neutral"> </span>
|
|
737
|
+
<span class="cline-any cline-no"> </span>
|
|
738
|
+
<span class="cline-any cline-neutral"> </span>
|
|
739
|
+
<span class="cline-any cline-no"> </span>
|
|
740
|
+
<span class="cline-any cline-neutral"> </span>
|
|
741
|
+
<span class="cline-any cline-no"> </span>
|
|
742
|
+
<span class="cline-any cline-no"> </span>
|
|
743
|
+
<span class="cline-any cline-no"> </span>
|
|
744
|
+
<span class="cline-any cline-no"> </span>
|
|
745
|
+
<span class="cline-any cline-no"> </span>
|
|
746
|
+
<span class="cline-any cline-no"> </span>
|
|
747
|
+
<span class="cline-any cline-no"> </span>
|
|
748
|
+
<span class="cline-any cline-no"> </span>
|
|
749
|
+
<span class="cline-any cline-no"> </span>
|
|
750
|
+
<span class="cline-any cline-no"> </span>
|
|
751
|
+
<span class="cline-any cline-no"> </span>
|
|
752
|
+
<span class="cline-any cline-no"> </span>
|
|
753
|
+
<span class="cline-any cline-no"> </span>
|
|
754
|
+
<span class="cline-any cline-no"> </span>
|
|
755
|
+
<span class="cline-any cline-neutral"> </span>
|
|
756
|
+
<span class="cline-any cline-neutral"> </span>
|
|
757
|
+
<span class="cline-any cline-no"> </span>
|
|
758
|
+
<span class="cline-any cline-no"> </span>
|
|
759
|
+
<span class="cline-any cline-no"> </span>
|
|
760
|
+
<span class="cline-any cline-no"> </span>
|
|
761
|
+
<span class="cline-any cline-no"> </span>
|
|
762
|
+
<span class="cline-any cline-no"> </span>
|
|
763
|
+
<span class="cline-any cline-no"> </span>
|
|
764
|
+
<span class="cline-any cline-no"> </span>
|
|
765
|
+
<span class="cline-any cline-no"> </span>
|
|
766
|
+
<span class="cline-any cline-no"> </span>
|
|
767
|
+
<span class="cline-any cline-no"> </span>
|
|
768
|
+
<span class="cline-any cline-no"> </span>
|
|
769
|
+
<span class="cline-any cline-no"> </span>
|
|
770
|
+
<span class="cline-any cline-no"> </span>
|
|
771
|
+
<span class="cline-any cline-no"> </span>
|
|
772
|
+
<span class="cline-any cline-no"> </span>
|
|
773
|
+
<span class="cline-any cline-no"> </span>
|
|
774
|
+
<span class="cline-any cline-no"> </span>
|
|
775
|
+
<span class="cline-any cline-no"> </span>
|
|
776
|
+
<span class="cline-any cline-no"> </span>
|
|
777
|
+
<span class="cline-any cline-no"> </span>
|
|
778
|
+
<span class="cline-any cline-no"> </span>
|
|
779
|
+
<span class="cline-any cline-neutral"> </span>
|
|
780
|
+
<span class="cline-any cline-neutral"> </span>
|
|
781
|
+
<span class="cline-any cline-no"> </span>
|
|
782
|
+
<span class="cline-any cline-no"> </span>
|
|
783
|
+
<span class="cline-any cline-no"> </span>
|
|
784
|
+
<span class="cline-any cline-neutral"> </span>
|
|
785
|
+
<span class="cline-any cline-neutral"> </span>
|
|
786
|
+
<span class="cline-any cline-no"> </span>
|
|
787
|
+
<span class="cline-any cline-neutral"> </span>
|
|
788
|
+
<span class="cline-any cline-neutral"> </span>
|
|
789
|
+
<span class="cline-any cline-no"> </span>
|
|
790
|
+
<span class="cline-any cline-no"> </span>
|
|
791
|
+
<span class="cline-any cline-no"> </span>
|
|
792
|
+
<span class="cline-any cline-neutral"> </span>
|
|
793
|
+
<span class="cline-any cline-neutral"> </span>
|
|
794
|
+
<span class="cline-any cline-neutral"> </span>
|
|
795
|
+
<span class="cline-any cline-no"> </span>
|
|
796
|
+
<span class="cline-any cline-no"> </span>
|
|
797
|
+
<span class="cline-any cline-no"> </span>
|
|
798
|
+
<span class="cline-any cline-no"> </span>
|
|
799
|
+
<span class="cline-any cline-neutral"> </span>
|
|
800
|
+
<span class="cline-any cline-no"> </span>
|
|
801
|
+
<span class="cline-any cline-neutral"> </span>
|
|
802
|
+
<span class="cline-any cline-neutral"> </span>
|
|
803
|
+
<span class="cline-any cline-no"> </span>
|
|
804
|
+
<span class="cline-any cline-no"> </span>
|
|
805
|
+
<span class="cline-any cline-no"> </span>
|
|
806
|
+
<span class="cline-any cline-no"> </span>
|
|
807
|
+
<span class="cline-any cline-no"> </span>
|
|
808
|
+
<span class="cline-any cline-no"> </span>
|
|
809
|
+
<span class="cline-any cline-no"> </span>
|
|
810
|
+
<span class="cline-any cline-no"> </span>
|
|
811
|
+
<span class="cline-any cline-no"> </span>
|
|
812
|
+
<span class="cline-any cline-no"> </span>
|
|
813
|
+
<span class="cline-any cline-no"> </span>
|
|
814
|
+
<span class="cline-any cline-no"> </span>
|
|
815
|
+
<span class="cline-any cline-no"> </span>
|
|
816
|
+
<span class="cline-any cline-neutral"> </span>
|
|
817
|
+
<span class="cline-any cline-no"> </span>
|
|
818
|
+
<span class="cline-any cline-no"> </span>
|
|
819
|
+
<span class="cline-any cline-no"> </span>
|
|
820
|
+
<span class="cline-any cline-neutral"> </span>
|
|
821
|
+
<span class="cline-any cline-neutral"> </span>
|
|
822
|
+
<span class="cline-any cline-no"> </span>
|
|
823
|
+
<span class="cline-any cline-no"> </span>
|
|
824
|
+
<span class="cline-any cline-no"> </span>
|
|
825
|
+
<span class="cline-any cline-no"> </span>
|
|
826
|
+
<span class="cline-any cline-no"> </span>
|
|
827
|
+
<span class="cline-any cline-no"> </span>
|
|
828
|
+
<span class="cline-any cline-no"> </span>
|
|
829
|
+
<span class="cline-any cline-no"> </span>
|
|
830
|
+
<span class="cline-any cline-no"> </span>
|
|
831
|
+
<span class="cline-any cline-no"> </span>
|
|
832
|
+
<span class="cline-any cline-no"> </span>
|
|
833
|
+
<span class="cline-any cline-no"> </span>
|
|
834
|
+
<span class="cline-any cline-no"> </span>
|
|
835
|
+
<span class="cline-any cline-no"> </span>
|
|
836
|
+
<span class="cline-any cline-no"> </span>
|
|
837
|
+
<span class="cline-any cline-no"> </span>
|
|
838
|
+
<span class="cline-any cline-no"> </span>
|
|
839
|
+
<span class="cline-any cline-no"> </span>
|
|
840
|
+
<span class="cline-any cline-no"> </span>
|
|
841
|
+
<span class="cline-any cline-no"> </span>
|
|
842
|
+
<span class="cline-any cline-no"> </span>
|
|
843
|
+
<span class="cline-any cline-no"> </span>
|
|
844
|
+
<span class="cline-any cline-no"> </span>
|
|
845
|
+
<span class="cline-any cline-no"> </span>
|
|
846
|
+
<span class="cline-any cline-no"> </span>
|
|
847
|
+
<span class="cline-any cline-no"> </span>
|
|
848
|
+
<span class="cline-any cline-no"> </span>
|
|
849
|
+
<span class="cline-any cline-no"> </span>
|
|
850
|
+
<span class="cline-any cline-no"> </span>
|
|
851
|
+
<span class="cline-any cline-no"> </span>
|
|
852
|
+
<span class="cline-any cline-no"> </span>
|
|
853
|
+
<span class="cline-any cline-no"> </span>
|
|
854
|
+
<span class="cline-any cline-no"> </span>
|
|
855
|
+
<span class="cline-any cline-no"> </span>
|
|
856
|
+
<span class="cline-any cline-no"> </span>
|
|
857
|
+
<span class="cline-any cline-no"> </span>
|
|
858
|
+
<span class="cline-any cline-no"> </span>
|
|
859
|
+
<span class="cline-any cline-no"> </span>
|
|
860
|
+
<span class="cline-any cline-no"> </span>
|
|
861
|
+
<span class="cline-any cline-no"> </span>
|
|
862
|
+
<span class="cline-any cline-no"> </span>
|
|
863
|
+
<span class="cline-any cline-no"> </span>
|
|
864
|
+
<span class="cline-any cline-no"> </span>
|
|
865
|
+
<span class="cline-any cline-no"> </span>
|
|
866
|
+
<span class="cline-any cline-no"> </span>
|
|
867
|
+
<span class="cline-any cline-no"> </span>
|
|
868
|
+
<span class="cline-any cline-no"> </span>
|
|
869
|
+
<span class="cline-any cline-no"> </span>
|
|
870
|
+
<span class="cline-any cline-no"> </span>
|
|
871
|
+
<span class="cline-any cline-no"> </span>
|
|
872
|
+
<span class="cline-any cline-no"> </span>
|
|
873
|
+
<span class="cline-any cline-no"> </span>
|
|
874
|
+
<span class="cline-any cline-no"> </span>
|
|
875
|
+
<span class="cline-any cline-no"> </span>
|
|
876
|
+
<span class="cline-any cline-no"> </span>
|
|
877
|
+
<span class="cline-any cline-no"> </span>
|
|
878
|
+
<span class="cline-any cline-no"> </span>
|
|
879
|
+
<span class="cline-any cline-no"> </span>
|
|
880
|
+
<span class="cline-any cline-no"> </span>
|
|
881
|
+
<span class="cline-any cline-no"> </span>
|
|
882
|
+
<span class="cline-any cline-neutral"> </span>
|
|
883
|
+
<span class="cline-any cline-no"> </span>
|
|
884
|
+
<span class="cline-any cline-no"> </span>
|
|
885
|
+
<span class="cline-any cline-no"> </span>
|
|
886
|
+
<span class="cline-any cline-neutral"> </span>
|
|
887
|
+
<span class="cline-any cline-neutral"> </span>
|
|
888
|
+
<span class="cline-any cline-no"> </span>
|
|
889
|
+
<span class="cline-any cline-neutral"> </span>
|
|
890
|
+
<span class="cline-any cline-neutral"> </span>
|
|
891
|
+
<span class="cline-any cline-no"> </span>
|
|
892
|
+
<span class="cline-any cline-no"> </span>
|
|
893
|
+
<span class="cline-any cline-no"> </span>
|
|
894
|
+
<span class="cline-any cline-neutral"> </span>
|
|
895
|
+
<span class="cline-any cline-neutral"> </span>
|
|
896
|
+
<span class="cline-any cline-no"> </span>
|
|
897
|
+
<span class="cline-any cline-neutral"> </span>
|
|
898
|
+
<span class="cline-any cline-no"> </span>
|
|
899
|
+
<span class="cline-any cline-no"> </span>
|
|
900
|
+
<span class="cline-any cline-no"> </span>
|
|
901
|
+
<span class="cline-any cline-no"> </span>
|
|
902
|
+
<span class="cline-any cline-no"> </span>
|
|
903
|
+
<span class="cline-any cline-no"> </span>
|
|
904
|
+
<span class="cline-any cline-no"> </span>
|
|
905
|
+
<span class="cline-any cline-no"> </span>
|
|
906
|
+
<span class="cline-any cline-neutral"> </span>
|
|
907
|
+
<span class="cline-any cline-no"> </span>
|
|
908
|
+
<span class="cline-any cline-no"> </span>
|
|
909
|
+
<span class="cline-any cline-no"> </span>
|
|
910
|
+
<span class="cline-any cline-no"> </span>
|
|
911
|
+
<span class="cline-any cline-no"> </span>
|
|
912
|
+
<span class="cline-any cline-no"> </span>
|
|
913
|
+
<span class="cline-any cline-no"> </span>
|
|
914
|
+
<span class="cline-any cline-no"> </span>
|
|
915
|
+
<span class="cline-any cline-neutral"> </span>
|
|
916
|
+
<span class="cline-any cline-neutral"> </span>
|
|
917
|
+
<span class="cline-any cline-no"> </span>
|
|
918
|
+
<span class="cline-any cline-no"> </span>
|
|
919
|
+
<span class="cline-any cline-no"> </span>
|
|
920
|
+
<span class="cline-any cline-no"> </span>
|
|
921
|
+
<span class="cline-any cline-no"> </span>
|
|
922
|
+
<span class="cline-any cline-no"> </span>
|
|
923
|
+
<span class="cline-any cline-no"> </span>
|
|
924
|
+
<span class="cline-any cline-no"> </span>
|
|
925
|
+
<span class="cline-any cline-neutral"> </span>
|
|
926
|
+
<span class="cline-any cline-neutral"> </span>
|
|
927
|
+
<span class="cline-any cline-no"> </span>
|
|
928
|
+
<span class="cline-any cline-no"> </span>
|
|
929
|
+
<span class="cline-any cline-no"> </span>
|
|
930
|
+
<span class="cline-any cline-no"> </span>
|
|
931
|
+
<span class="cline-any cline-no"> </span>
|
|
932
|
+
<span class="cline-any cline-no"> </span>
|
|
933
|
+
<span class="cline-any cline-no"> </span>
|
|
934
|
+
<span class="cline-any cline-no"> </span>
|
|
935
|
+
<span class="cline-any cline-neutral"> </span>
|
|
936
|
+
<span class="cline-any cline-neutral"> </span>
|
|
937
|
+
<span class="cline-any cline-no"> </span>
|
|
938
|
+
<span class="cline-any cline-no"> </span>
|
|
939
|
+
<span class="cline-any cline-no"> </span>
|
|
940
|
+
<span class="cline-any cline-no"> </span>
|
|
941
|
+
<span class="cline-any cline-no"> </span>
|
|
942
|
+
<span class="cline-any cline-no"> </span>
|
|
943
|
+
<span class="cline-any cline-no"> </span>
|
|
944
|
+
<span class="cline-any cline-no"> </span>
|
|
945
|
+
<span class="cline-any cline-no"> </span>
|
|
946
|
+
<span class="cline-any cline-neutral"> </span>
|
|
947
|
+
<span class="cline-any cline-no"> </span>
|
|
948
|
+
<span class="cline-any cline-no"> </span>
|
|
949
|
+
<span class="cline-any cline-no"> </span>
|
|
950
|
+
<span class="cline-any cline-neutral"> </span>
|
|
951
|
+
<span class="cline-any cline-no"> </span>
|
|
952
|
+
<span class="cline-any cline-neutral"> </span>
|
|
953
|
+
<span class="cline-any cline-neutral"> </span>
|
|
954
|
+
<span class="cline-any cline-no"> </span>
|
|
955
|
+
<span class="cline-any cline-no"> </span>
|
|
956
|
+
<span class="cline-any cline-neutral"> </span>
|
|
957
|
+
<span class="cline-any cline-no"> </span>
|
|
958
|
+
<span class="cline-any cline-no"> </span>
|
|
959
|
+
<span class="cline-any cline-no"> </span>
|
|
960
|
+
<span class="cline-any cline-neutral"> </span>
|
|
961
|
+
<span class="cline-any cline-neutral"> </span>
|
|
962
|
+
<span class="cline-any cline-no"> </span>
|
|
963
|
+
<span class="cline-any cline-neutral"> </span>
|
|
964
|
+
<span class="cline-any cline-neutral"> </span>
|
|
965
|
+
<span class="cline-any cline-no"> </span>
|
|
966
|
+
<span class="cline-any cline-no"> </span>
|
|
967
|
+
<span class="cline-any cline-no"> </span>
|
|
968
|
+
<span class="cline-any cline-no"> </span>
|
|
969
|
+
<span class="cline-any cline-no"> </span>
|
|
970
|
+
<span class="cline-any cline-no"> </span>
|
|
971
|
+
<span class="cline-any cline-neutral"> </span>
|
|
972
|
+
<span class="cline-any cline-neutral"> </span>
|
|
973
|
+
<span class="cline-any cline-no"> </span>
|
|
974
|
+
<span class="cline-any cline-no"> </span>
|
|
975
|
+
<span class="cline-any cline-neutral"> </span>
|
|
976
|
+
<span class="cline-any cline-no"> </span>
|
|
977
|
+
<span class="cline-any cline-no"> </span>
|
|
978
|
+
<span class="cline-any cline-no"> </span>
|
|
979
|
+
<span class="cline-any cline-no"> </span>
|
|
980
|
+
<span class="cline-any cline-no"> </span>
|
|
981
|
+
<span class="cline-any cline-no"> </span>
|
|
982
|
+
<span class="cline-any cline-neutral"> </span>
|
|
983
|
+
<span class="cline-any cline-no"> </span>
|
|
984
|
+
<span class="cline-any cline-no"> </span>
|
|
985
|
+
<span class="cline-any cline-no"> </span>
|
|
986
|
+
<span class="cline-any cline-no"> </span>
|
|
987
|
+
<span class="cline-any cline-no"> </span>
|
|
988
|
+
<span class="cline-any cline-neutral"> </span>
|
|
989
|
+
<span class="cline-any cline-no"> </span>
|
|
990
|
+
<span class="cline-any cline-no"> </span>
|
|
991
|
+
<span class="cline-any cline-neutral"> </span>
|
|
992
|
+
<span class="cline-any cline-neutral"> </span>
|
|
993
|
+
<span class="cline-any cline-no"> </span>
|
|
994
|
+
<span class="cline-any cline-no"> </span>
|
|
995
|
+
<span class="cline-any cline-no"> </span>
|
|
996
|
+
<span class="cline-any cline-neutral"> </span>
|
|
997
|
+
<span class="cline-any cline-no"> </span>
|
|
998
|
+
<span class="cline-any cline-no"> </span>
|
|
999
|
+
<span class="cline-any cline-no"> </span>
|
|
1000
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1001
|
+
<span class="cline-any cline-no"> </span>
|
|
1002
|
+
<span class="cline-any cline-no"> </span>
|
|
1003
|
+
<span class="cline-any cline-no"> </span>
|
|
1004
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1005
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1006
|
+
<span class="cline-any cline-no"> </span>
|
|
1007
|
+
<span class="cline-any cline-no"> </span>
|
|
1008
|
+
<span class="cline-any cline-no"> </span>
|
|
1009
|
+
<span class="cline-any cline-no"> </span>
|
|
1010
|
+
<span class="cline-any cline-no"> </span>
|
|
1011
|
+
<span class="cline-any cline-no"> </span>
|
|
1012
|
+
<span class="cline-any cline-no"> </span>
|
|
1013
|
+
<span class="cline-any cline-no"> </span>
|
|
1014
|
+
<span class="cline-any cline-no"> </span>
|
|
1015
|
+
<span class="cline-any cline-no"> </span>
|
|
1016
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1017
|
+
<span class="cline-any cline-no"> </span>
|
|
1018
|
+
<span class="cline-any cline-no"> </span>
|
|
1019
|
+
<span class="cline-any cline-no"> </span>
|
|
1020
|
+
<span class="cline-any cline-no"> </span>
|
|
1021
|
+
<span class="cline-any cline-no"> </span>
|
|
1022
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1023
|
+
<span class="cline-any cline-no"> </span>
|
|
1024
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1025
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1026
|
+
<span class="cline-any cline-no"> </span>
|
|
1027
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1028
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1029
|
+
<span class="cline-any cline-no"> </span>
|
|
1030
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1031
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1032
|
+
<span class="cline-any cline-no"> </span>
|
|
1033
|
+
<span class="cline-any cline-no"> </span>
|
|
1034
|
+
<span class="cline-any cline-no"> </span>
|
|
1035
|
+
<span class="cline-any cline-no"> </span>
|
|
1036
|
+
<span class="cline-any cline-no"> </span>
|
|
1037
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1038
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1039
|
+
<span class="cline-any cline-no"> </span>
|
|
1040
|
+
<span class="cline-any cline-no"> </span>
|
|
1041
|
+
<span class="cline-any cline-no"> </span>
|
|
1042
|
+
<span class="cline-any cline-no"> </span>
|
|
1043
|
+
<span class="cline-any cline-no"> </span>
|
|
1044
|
+
<span class="cline-any cline-no"> </span>
|
|
1045
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1046
|
+
<span class="cline-any cline-no"> </span>
|
|
1047
|
+
<span class="cline-any cline-no"> </span>
|
|
1048
|
+
<span class="cline-any cline-no"> </span>
|
|
1049
|
+
<span class="cline-any cline-no"> </span>
|
|
1050
|
+
<span class="cline-any cline-no"> </span>
|
|
1051
|
+
<span class="cline-any cline-no"> </span>
|
|
1052
|
+
<span class="cline-any cline-no"> </span>
|
|
1053
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1054
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1055
|
+
<span class="cline-any cline-no"> </span>
|
|
1056
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1057
|
+
<span class="cline-any cline-no"> </span>
|
|
1058
|
+
<span class="cline-any cline-no"> </span>
|
|
1059
|
+
<span class="cline-any cline-no"> </span>
|
|
1060
|
+
<span class="cline-any cline-no"> </span>
|
|
1061
|
+
<span class="cline-any cline-no"> </span>
|
|
1062
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1063
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1064
|
+
<span class="cline-any cline-no"> </span>
|
|
1065
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1066
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1067
|
+
<span class="cline-any cline-no"> </span>
|
|
1068
|
+
<span class="cline-any cline-no"> </span>
|
|
1069
|
+
<span class="cline-any cline-no"> </span>
|
|
1070
|
+
<span class="cline-any cline-no"> </span>
|
|
1071
|
+
<span class="cline-any cline-no"> </span>
|
|
1072
|
+
<span class="cline-any cline-no"> </span>
|
|
1073
|
+
<span class="cline-any cline-no"> </span>
|
|
1074
|
+
<span class="cline-any cline-no"> </span>
|
|
1075
|
+
<span class="cline-any cline-no"> </span>
|
|
1076
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1077
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1078
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1079
|
+
<span class="cline-any cline-no"> </span>
|
|
1080
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1081
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1082
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1083
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1084
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1085
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1086
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1087
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1088
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1089
|
+
<span class="cline-any cline-no"> </span>
|
|
1090
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1091
|
+
<span class="cline-any cline-no"> </span>
|
|
1092
|
+
<span class="cline-any cline-no"> </span>
|
|
1093
|
+
<span class="cline-any cline-no"> </span>
|
|
1094
|
+
<span class="cline-any cline-no"> </span>
|
|
1095
|
+
<span class="cline-any cline-no"> </span>
|
|
1096
|
+
<span class="cline-any cline-no"> </span>
|
|
1097
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1098
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1099
|
+
<span class="cline-any cline-no"> </span>
|
|
1100
|
+
<span class="cline-any cline-no"> </span>
|
|
1101
|
+
<span class="cline-any cline-no"> </span>
|
|
1102
|
+
<span class="cline-any cline-no"> </span>
|
|
1103
|
+
<span class="cline-any cline-no"> </span>
|
|
1104
|
+
<span class="cline-any cline-no"> </span>
|
|
1105
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1106
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1107
|
+
<span class="cline-any cline-no"> </span>
|
|
1108
|
+
<span class="cline-any cline-no"> </span>
|
|
1109
|
+
<span class="cline-any cline-no"> </span>
|
|
1110
|
+
<span class="cline-any cline-no"> </span>
|
|
1111
|
+
<span class="cline-any cline-no"> </span>
|
|
1112
|
+
<span class="cline-any cline-no"> </span>
|
|
1113
|
+
<span class="cline-any cline-no"> </span>
|
|
1114
|
+
<span class="cline-any cline-no"> </span>
|
|
1115
|
+
<span class="cline-any cline-no"> </span>
|
|
1116
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1117
|
+
<span class="cline-any cline-no"> </span>
|
|
1118
|
+
<span class="cline-any cline-no"> </span>
|
|
1119
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1120
|
+
<span class="cline-any cline-no"> </span>
|
|
1121
|
+
<span class="cline-any cline-no"> </span>
|
|
1122
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1123
|
+
<span class="cline-any cline-no"> </span>
|
|
1124
|
+
<span class="cline-any cline-no"> </span>
|
|
1125
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1126
|
+
<span class="cline-any cline-no"> </span>
|
|
1127
|
+
<span class="cline-any cline-no"> </span>
|
|
1128
|
+
<span class="cline-any cline-no"> </span>
|
|
1129
|
+
<span class="cline-any cline-no"> </span>
|
|
1130
|
+
<span class="cline-any cline-no"> </span>
|
|
1131
|
+
<span class="cline-any cline-no"> </span>
|
|
1132
|
+
<span class="cline-any cline-no"> </span>
|
|
1133
|
+
<span class="cline-any cline-no"> </span>
|
|
1134
|
+
<span class="cline-any cline-no"> </span>
|
|
1135
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1136
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1137
|
+
<span class="cline-any cline-no"> </span>
|
|
1138
|
+
<span class="cline-any cline-no"> </span>
|
|
1139
|
+
<span class="cline-any cline-no"> </span>
|
|
1140
|
+
<span class="cline-any cline-no"> </span>
|
|
1141
|
+
<span class="cline-any cline-no"> </span>
|
|
1142
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1143
|
+
<span class="cline-any cline-no"> </span>
|
|
1144
|
+
<span class="cline-any cline-no"> </span></td><td class="text"><pre class="prettyprint lang-js"><span class="cstat-no" title="statement not covered" ><span class="fstat-no" title="function not covered" ><span class="branch-0 cbranch-no" title="branch not covered" >import express from 'express';</span></span></span>
|
|
1145
|
+
import type { Request, Response } from 'express';
|
|
1146
|
+
<span class="cstat-no" title="statement not covered" >import { createServer } from 'http';</span>
|
|
1147
|
+
<span class="cstat-no" title="statement not covered" >import { Server } from 'socket.io';</span>
|
|
1148
|
+
<span class="cstat-no" title="statement not covered" >import cors from 'cors';</span>
|
|
1149
|
+
import dotenv from 'dotenv';
|
|
1150
|
+
<span class="cstat-no" title="statement not covered" >import { createExpressMiddleware } from '@trpc/server/adapters/express';</span>
|
|
1151
|
+
<span class="cstat-no" title="statement not covered" >import { appRouter } from './routers/_app.js';</span>
|
|
1152
|
+
<span class="cstat-no" title="statement not covered" >import { createTRPCContext, createCallerFactory } from './trpc.js';</span>
|
|
1153
|
+
<span class="cstat-no" title="statement not covered" >import { logger } from './utils/logger.js';</span>
|
|
1154
|
+
<span class="cstat-no" title="statement not covered" >import { setupSocketHandlers } from './socket/handlers.js';</span>
|
|
1155
|
+
<span class="cstat-no" title="statement not covered" >import { bucket } from './lib/googleCloudStorage.js';</span>
|
|
1156
|
+
<span class="cstat-no" title="statement not covered" >import { prisma } from './lib/prisma.js';</span>
|
|
1157
|
+
|
|
1158
|
+
<span class="cstat-no" title="statement not covered" >import { authLimiter, generalLimiter, helmetConfig, uploadLimiter } from './middleware/security.js';</span>
|
|
1159
|
+
|
|
1160
|
+
<span class="cstat-no" title="statement not covered" >import * as Sentry from "@sentry/node";</span>
|
|
1161
|
+
<span class="cstat-no" title="statement not covered" >import { env } from './lib/config/env.js';</span>
|
|
1162
|
+
<span class="cstat-no" title="statement not covered" >import compression from 'compression';</span>
|
|
1163
|
+
<span class="cstat-no" title="statement not covered" >import { v4 as uuidv4 } from 'uuid';</span>
|
|
1164
|
+
|
|
1165
|
+
|
|
1166
|
+
<span class="cstat-no" title="statement not covered" >import "./instrument.js";</span>
|
|
1167
|
+
|
|
1168
|
+
<span class="cstat-no" title="statement not covered" >const app = express();</span>
|
|
1169
|
+
|
|
1170
|
+
<span class="cstat-no" title="statement not covered" >app.use(helmetConfig);</span>
|
|
1171
|
+
<span class="cstat-no" title="statement not covered" >app.use(compression());</span>
|
|
1172
|
+
|
|
1173
|
+
<span class="cstat-no" title="statement not covered" >app.use((req, res, next) => {</span>
|
|
1174
|
+
<span class="cstat-no" title="statement not covered" > const requestId = uuidv4();</span>
|
|
1175
|
+
<span class="cstat-no" title="statement not covered" > res.setHeader('X-Request-ID', requestId);</span>
|
|
1176
|
+
<span class="cstat-no" title="statement not covered" > next();</span>
|
|
1177
|
+
<span class="cstat-no" title="statement not covered" >});</span>
|
|
1178
|
+
|
|
1179
|
+
<span class="cstat-no" title="statement not covered" >app.use(generalLimiter);</span>
|
|
1180
|
+
|
|
1181
|
+
<span class="cstat-no" title="statement not covered" >const allowedOrigins = env.NODE_ENV === 'production'</span>
|
|
1182
|
+
<span class="cstat-no" title="statement not covered" >? [</span>
|
|
1183
|
+
<span class="cstat-no" title="statement not covered" > 'https://www.studious.sh',</span>
|
|
1184
|
+
<span class="cstat-no" title="statement not covered" > 'https://studious.sh',</span>
|
|
1185
|
+
<span class="cstat-no" title="statement not covered" > env.NEXT_PUBLIC_APP_URL,</span>
|
|
1186
|
+
<span class="cstat-no" title="statement not covered" > 'http://localhost:3000',</span>
|
|
1187
|
+
|
|
1188
|
+
<span class="cstat-no" title="statement not covered" > ].filter(Boolean)</span>
|
|
1189
|
+
<span class="cstat-no" title="statement not covered" >: [</span>
|
|
1190
|
+
<span class="cstat-no" title="statement not covered" > 'http://localhost:3000',</span>
|
|
1191
|
+
<span class="cstat-no" title="statement not covered" > 'http://localhost:3001',</span>
|
|
1192
|
+
<span class="cstat-no" title="statement not covered" > 'http://127.0.0.1:3000',</span>
|
|
1193
|
+
<span class="cstat-no" title="statement not covered" > 'http://127.0.0.1:3001',</span>
|
|
1194
|
+
|
|
1195
|
+
<span class="cstat-no" title="statement not covered" > env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'</span>
|
|
1196
|
+
<span class="cstat-no" title="statement not covered" > ];</span>
|
|
1197
|
+
|
|
1198
|
+
// CORS middleware
|
|
1199
|
+
<span class="cstat-no" title="statement not covered" >app.use(cors({</span>
|
|
1200
|
+
<span class="cstat-no" title="statement not covered" > origin: allowedOrigins,</span>
|
|
1201
|
+
<span class="cstat-no" title="statement not covered" > credentials: true,</span>
|
|
1202
|
+
<span class="cstat-no" title="statement not covered" > methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],</span>
|
|
1203
|
+
<span class="cstat-no" title="statement not covered" > allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With', 'x-user'],</span>
|
|
1204
|
+
<span class="cstat-no" title="statement not covered" > optionsSuccessStatus: 200</span>
|
|
1205
|
+
<span class="cstat-no" title="statement not covered" >}));</span>
|
|
1206
|
+
|
|
1207
|
+
// Handle preflight OPTIONS requests
|
|
1208
|
+
<span class="cstat-no" title="statement not covered" >app.options('*', (req, res) => {</span>
|
|
1209
|
+
<span class="cstat-no" title="statement not covered" > const origin = req.headers.origin;</span>
|
|
1210
|
+
<span class="cstat-no" title="statement not covered" > if (origin && allowedOrigins.includes(origin)) {</span>
|
|
1211
|
+
<span class="cstat-no" title="statement not covered" > res.header('Access-Control-Allow-Origin', origin);</span>
|
|
1212
|
+
<span class="cstat-no" title="statement not covered" > } else {</span>
|
|
1213
|
+
<span class="cstat-no" title="statement not covered" > res.header('Access-Control-Allow-Origin', 'http://localhost:3000');</span>
|
|
1214
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1215
|
+
|
|
1216
|
+
<span class="cstat-no" title="statement not covered" > res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');</span>
|
|
1217
|
+
<span class="cstat-no" title="statement not covered" > res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With, x-user');</span>
|
|
1218
|
+
<span class="cstat-no" title="statement not covered" > res.header('Access-Control-Allow-Credentials', 'true');</span>
|
|
1219
|
+
<span class="cstat-no" title="statement not covered" > res.sendStatus(200);</span>
|
|
1220
|
+
<span class="cstat-no" title="statement not covered" >});</span>
|
|
1221
|
+
|
|
1222
|
+
// CORS debugging middleware
|
|
1223
|
+
<span class="cstat-no" title="statement not covered" >app.use((req, res, next) => {</span>
|
|
1224
|
+
<span class="cstat-no" title="statement not covered" > if (req.method === 'OPTIONS' || req.path.includes('trpc')) {</span>
|
|
1225
|
+
<span class="cstat-no" title="statement not covered" > logger.info('CORS Request', {</span>
|
|
1226
|
+
<span class="cstat-no" title="statement not covered" > method: req.method,</span>
|
|
1227
|
+
<span class="cstat-no" title="statement not covered" > path: req.path,</span>
|
|
1228
|
+
<span class="cstat-no" title="statement not covered" > origin: req.headers.origin,</span>
|
|
1229
|
+
<span class="cstat-no" title="statement not covered" > userAgent: req.headers['user-agent']</span>
|
|
1230
|
+
<span class="cstat-no" title="statement not covered" > });</span>
|
|
1231
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1232
|
+
<span class="cstat-no" title="statement not covered" > next();</span>
|
|
1233
|
+
<span class="cstat-no" title="statement not covered" >});</span>
|
|
1234
|
+
|
|
1235
|
+
// Response time logging middleware
|
|
1236
|
+
<span class="cstat-no" title="statement not covered" >app.use((req, res, next) => {</span>
|
|
1237
|
+
<span class="cstat-no" title="statement not covered" > const start = Date.now();</span>
|
|
1238
|
+
<span class="cstat-no" title="statement not covered" > res.on('finish', () => {</span>
|
|
1239
|
+
<span class="cstat-no" title="statement not covered" > const duration = Date.now() - start;</span>
|
|
1240
|
+
<span class="cstat-no" title="statement not covered" > logger.info('Request completed', {</span>
|
|
1241
|
+
<span class="cstat-no" title="statement not covered" > method: req.method,</span>
|
|
1242
|
+
<span class="cstat-no" title="statement not covered" > path: req.path,</span>
|
|
1243
|
+
<span class="cstat-no" title="statement not covered" > statusCode: res.statusCode,</span>
|
|
1244
|
+
<span class="cstat-no" title="statement not covered" > duration: `${duration}ms`</span>
|
|
1245
|
+
<span class="cstat-no" title="statement not covered" > });</span>
|
|
1246
|
+
<span class="cstat-no" title="statement not covered" > });</span>
|
|
1247
|
+
<span class="cstat-no" title="statement not covered" > next();</span>
|
|
1248
|
+
<span class="cstat-no" title="statement not covered" >});</span>
|
|
1249
|
+
|
|
1250
|
+
<span class="cstat-no" title="statement not covered" >app.use("/panel", async (_, res) => {</span>
|
|
1251
|
+
<span class="cstat-no" title="statement not covered" > if (env.NODE_ENV !== "development") {</span>
|
|
1252
|
+
<span class="cstat-no" title="statement not covered" > return res.status(404).send("Not Found");</span>
|
|
1253
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1254
|
+
|
|
1255
|
+
// Dynamically import renderTrpcPanel only in development
|
|
1256
|
+
<span class="cstat-no" title="statement not covered" > const { renderTrpcPanel } = await import("trpc-ui");</span>
|
|
1257
|
+
|
|
1258
|
+
<span class="cstat-no" title="statement not covered" > return res.send(</span>
|
|
1259
|
+
<span class="cstat-no" title="statement not covered" > renderTrpcPanel(appRouter, {</span>
|
|
1260
|
+
<span class="cstat-no" title="statement not covered" > url: "/trpc", // Base url of your trpc server</span>
|
|
1261
|
+
<span class="cstat-no" title="statement not covered" > meta: {</span>
|
|
1262
|
+
<span class="cstat-no" title="statement not covered" > title: "Studious Backend",</span>
|
|
1263
|
+
<span class="cstat-no" title="statement not covered" > description:</span>
|
|
1264
|
+
<span class="cstat-no" title="statement not covered" > "This is the backend for the Studious application.",</span>
|
|
1265
|
+
<span class="cstat-no" title="statement not covered" > },</span>
|
|
1266
|
+
<span class="cstat-no" title="statement not covered" > })</span>
|
|
1267
|
+
<span class="cstat-no" title="statement not covered" > );</span>
|
|
1268
|
+
<span class="cstat-no" title="statement not covered" >});</span>
|
|
1269
|
+
|
|
1270
|
+
|
|
1271
|
+
// Create HTTP server
|
|
1272
|
+
<span class="cstat-no" title="statement not covered" >const httpServer = createServer(app);</span>
|
|
1273
|
+
|
|
1274
|
+
<span class="cstat-no" title="statement not covered" >app.get('/health', async (req, res) => {</span>
|
|
1275
|
+
|
|
1276
|
+
<span class="cstat-no" title="statement not covered" > try {</span>
|
|
1277
|
+
// Check database connectivity
|
|
1278
|
+
<span class="cstat-no" title="statement not covered" > await prisma.$queryRaw`SELECT 1`;</span>
|
|
1279
|
+
|
|
1280
|
+
<span class="cstat-no" title="statement not covered" > res.status(200).json({ </span>
|
|
1281
|
+
<span class="cstat-no" title="statement not covered" > status: 'OK',</span>
|
|
1282
|
+
<span class="cstat-no" title="statement not covered" > timestamp: new Date().toISOString(),</span>
|
|
1283
|
+
<span class="cstat-no" title="statement not covered" > uptime: process.uptime(),</span>
|
|
1284
|
+
<span class="cstat-no" title="statement not covered" > database: 'connected'</span>
|
|
1285
|
+
<span class="cstat-no" title="statement not covered" > });</span>
|
|
1286
|
+
<span class="cstat-no" title="statement not covered" > } catch (error) {</span>
|
|
1287
|
+
<span class="cstat-no" title="statement not covered" > res.status(503).json({ </span>
|
|
1288
|
+
<span class="cstat-no" title="statement not covered" > status: 'ERROR',</span>
|
|
1289
|
+
<span class="cstat-no" title="statement not covered" > database: 'disconnected',</span>
|
|
1290
|
+
<span class="cstat-no" title="statement not covered" > error: error instanceof Error ? error.message : 'Unknown error'</span>
|
|
1291
|
+
<span class="cstat-no" title="statement not covered" > });</span>
|
|
1292
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1293
|
+
<span class="cstat-no" title="statement not covered" >});</span>
|
|
1294
|
+
|
|
1295
|
+
// Setup Socket.IO
|
|
1296
|
+
<span class="cstat-no" title="statement not covered" >const io = new Server(httpServer, {</span>
|
|
1297
|
+
<span class="cstat-no" title="statement not covered" > cors: {</span>
|
|
1298
|
+
<span class="cstat-no" title="statement not covered" > origin: [</span>
|
|
1299
|
+
<span class="cstat-no" title="statement not covered" > 'http://localhost:3000', // Frontend development server</span>
|
|
1300
|
+
<span class="cstat-no" title="statement not covered" > 'http://localhost:3001', // Server port</span>
|
|
1301
|
+
<span class="cstat-no" title="statement not covered" > 'http://127.0.0.1:3000', // Alternative localhost</span>
|
|
1302
|
+
<span class="cstat-no" title="statement not covered" > 'http://127.0.0.1:3001', // Alternative localhost</span>
|
|
1303
|
+
<span class="cstat-no" title="statement not covered" > 'https://www.studious.sh', // Production frontend</span>
|
|
1304
|
+
<span class="cstat-no" title="statement not covered" > 'https://studious.sh', // Production frontend (without www)</span>
|
|
1305
|
+
<span class="cstat-no" title="statement not covered" > env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'</span>
|
|
1306
|
+
<span class="cstat-no" title="statement not covered" > ],</span>
|
|
1307
|
+
<span class="cstat-no" title="statement not covered" > methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],</span>
|
|
1308
|
+
<span class="cstat-no" title="statement not covered" > credentials: true,</span>
|
|
1309
|
+
<span class="cstat-no" title="statement not covered" > allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With', 'Access-Control-Allow-Origin', 'x-user']</span>
|
|
1310
|
+
<span class="cstat-no" title="statement not covered" > },</span>
|
|
1311
|
+
<span class="cstat-no" title="statement not covered" > transports: ['websocket', 'polling'],</span>
|
|
1312
|
+
<span class="cstat-no" title="statement not covered" > pingTimeout: 60000,</span>
|
|
1313
|
+
<span class="cstat-no" title="statement not covered" > pingInterval: 25000,</span>
|
|
1314
|
+
<span class="cstat-no" title="statement not covered" > connectTimeout: 45000,</span>
|
|
1315
|
+
<span class="cstat-no" title="statement not covered" > path: '/socket.io/',</span>
|
|
1316
|
+
<span class="cstat-no" title="statement not covered" > allowEIO3: true</span>
|
|
1317
|
+
<span class="cstat-no" title="statement not covered" >});</span>
|
|
1318
|
+
|
|
1319
|
+
// Add server-level logging
|
|
1320
|
+
<span class="cstat-no" title="statement not covered" >io.engine.on('connection_error', (err: Error) => {</span>
|
|
1321
|
+
<span class="cstat-no" title="statement not covered" > logger.error('Socket connection error', { error: err.message });</span>
|
|
1322
|
+
<span class="cstat-no" title="statement not covered" >});</span>
|
|
1323
|
+
|
|
1324
|
+
// Setup socket handlers
|
|
1325
|
+
<span class="cstat-no" title="statement not covered" >setupSocketHandlers(io);</span>
|
|
1326
|
+
|
|
1327
|
+
// File serving endpoint for secure file access
|
|
1328
|
+
<span class="cstat-no" title="statement not covered" >app.get('/api/files/:fileId', async (req, res) => {</span>
|
|
1329
|
+
<span class="cstat-no" title="statement not covered" > try {</span>
|
|
1330
|
+
<span class="cstat-no" title="statement not covered" > const fileId = decodeURIComponent(req.params.fileId);</span>
|
|
1331
|
+
// console.log('File request:', { fileId, originalPath: req.params.fileId });
|
|
1332
|
+
|
|
1333
|
+
// Get user from request headers
|
|
1334
|
+
<span class="cstat-no" title="statement not covered" > const userHeader = req.headers['x-user'];</span>
|
|
1335
|
+
<span class="cstat-no" title="statement not covered" > if (!userHeader) {</span>
|
|
1336
|
+
<span class="cstat-no" title="statement not covered" > return res.status(401).json({ error: 'Authentication required' });</span>
|
|
1337
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1338
|
+
|
|
1339
|
+
<span class="cstat-no" title="statement not covered" > const token = typeof userHeader === 'string' ? userHeader : userHeader[0];</span>
|
|
1340
|
+
|
|
1341
|
+
// Find user by session token
|
|
1342
|
+
<span class="cstat-no" title="statement not covered" > const user = await prisma.user.findFirst({</span>
|
|
1343
|
+
<span class="cstat-no" title="statement not covered" > where: {</span>
|
|
1344
|
+
<span class="cstat-no" title="statement not covered" > sessions: {</span>
|
|
1345
|
+
<span class="cstat-no" title="statement not covered" > some: {</span>
|
|
1346
|
+
<span class="cstat-no" title="statement not covered" > id: token</span>
|
|
1347
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1348
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1349
|
+
<span class="cstat-no" title="statement not covered" > },</span>
|
|
1350
|
+
<span class="cstat-no" title="statement not covered" > select: {</span>
|
|
1351
|
+
<span class="cstat-no" title="statement not covered" > id: true,</span>
|
|
1352
|
+
<span class="cstat-no" title="statement not covered" > username: true,</span>
|
|
1353
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1354
|
+
<span class="cstat-no" title="statement not covered" > });</span>
|
|
1355
|
+
|
|
1356
|
+
<span class="cstat-no" title="statement not covered" > if (!user) {</span>
|
|
1357
|
+
<span class="cstat-no" title="statement not covered" > return res.status(401).json({ error: 'Invalid or expired session' });</span>
|
|
1358
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1359
|
+
|
|
1360
|
+
// Find file in database by path
|
|
1361
|
+
<span class="cstat-no" title="statement not covered" > const fileRecord = await prisma.file.findFirst({</span>
|
|
1362
|
+
<span class="cstat-no" title="statement not covered" > where: { id: fileId },</span>
|
|
1363
|
+
<span class="cstat-no" title="statement not covered" > include: {</span>
|
|
1364
|
+
<span class="cstat-no" title="statement not covered" > user: true,</span>
|
|
1365
|
+
<span class="cstat-no" title="statement not covered" > assignment: {</span>
|
|
1366
|
+
<span class="cstat-no" title="statement not covered" > include: {</span>
|
|
1367
|
+
<span class="cstat-no" title="statement not covered" > class: {</span>
|
|
1368
|
+
<span class="cstat-no" title="statement not covered" > include: {</span>
|
|
1369
|
+
<span class="cstat-no" title="statement not covered" > students: true,</span>
|
|
1370
|
+
<span class="cstat-no" title="statement not covered" > teachers: true</span>
|
|
1371
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1372
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1373
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1374
|
+
<span class="cstat-no" title="statement not covered" > },</span>
|
|
1375
|
+
<span class="cstat-no" title="statement not covered" > submission: {</span>
|
|
1376
|
+
<span class="cstat-no" title="statement not covered" > include: {</span>
|
|
1377
|
+
<span class="cstat-no" title="statement not covered" > student: true,</span>
|
|
1378
|
+
<span class="cstat-no" title="statement not covered" > assignment: {</span>
|
|
1379
|
+
<span class="cstat-no" title="statement not covered" > include: {</span>
|
|
1380
|
+
<span class="cstat-no" title="statement not covered" > class: {</span>
|
|
1381
|
+
<span class="cstat-no" title="statement not covered" > include: {</span>
|
|
1382
|
+
<span class="cstat-no" title="statement not covered" > teachers: true</span>
|
|
1383
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1384
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1385
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1386
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1387
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1388
|
+
<span class="cstat-no" title="statement not covered" > },</span>
|
|
1389
|
+
<span class="cstat-no" title="statement not covered" > annotations: {</span>
|
|
1390
|
+
<span class="cstat-no" title="statement not covered" > include: {</span>
|
|
1391
|
+
<span class="cstat-no" title="statement not covered" > student: true,</span>
|
|
1392
|
+
<span class="cstat-no" title="statement not covered" > assignment: {</span>
|
|
1393
|
+
<span class="cstat-no" title="statement not covered" > include: {</span>
|
|
1394
|
+
<span class="cstat-no" title="statement not covered" > class: {</span>
|
|
1395
|
+
<span class="cstat-no" title="statement not covered" > include: {</span>
|
|
1396
|
+
<span class="cstat-no" title="statement not covered" > teachers: true</span>
|
|
1397
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1398
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1399
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1400
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1401
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1402
|
+
<span class="cstat-no" title="statement not covered" > },</span>
|
|
1403
|
+
<span class="cstat-no" title="statement not covered" > folder: {</span>
|
|
1404
|
+
<span class="cstat-no" title="statement not covered" > include: {</span>
|
|
1405
|
+
<span class="cstat-no" title="statement not covered" > class: {</span>
|
|
1406
|
+
<span class="cstat-no" title="statement not covered" > include: {</span>
|
|
1407
|
+
<span class="cstat-no" title="statement not covered" > students: true,</span>
|
|
1408
|
+
<span class="cstat-no" title="statement not covered" > teachers: true</span>
|
|
1409
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1410
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1411
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1412
|
+
<span class="cstat-no" title="statement not covered" > },</span>
|
|
1413
|
+
<span class="cstat-no" title="statement not covered" > classDraft: {</span>
|
|
1414
|
+
<span class="cstat-no" title="statement not covered" > include: {</span>
|
|
1415
|
+
<span class="cstat-no" title="statement not covered" > students: true,</span>
|
|
1416
|
+
<span class="cstat-no" title="statement not covered" > teachers: true</span>
|
|
1417
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1418
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1419
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1420
|
+
<span class="cstat-no" title="statement not covered" > });</span>
|
|
1421
|
+
|
|
1422
|
+
<span class="cstat-no" title="statement not covered" > if (!fileRecord) {</span>
|
|
1423
|
+
<span class="cstat-no" title="statement not covered" > return res.status(404).json({ error: 'File not found in database' });</span>
|
|
1424
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1425
|
+
|
|
1426
|
+
// Check if user has permission to access this file
|
|
1427
|
+
<span class="cstat-no" title="statement not covered" > let hasPermission = false;</span>
|
|
1428
|
+
|
|
1429
|
+
// Check if user created the file
|
|
1430
|
+
<span class="cstat-no" title="statement not covered" > if (fileRecord.userId === user.id) {</span>
|
|
1431
|
+
<span class="cstat-no" title="statement not covered" > hasPermission = true;</span>
|
|
1432
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1433
|
+
|
|
1434
|
+
// Check if file is related to a class where user is a member
|
|
1435
|
+
<span class="cstat-no" title="statement not covered" > if (!hasPermission) {</span>
|
|
1436
|
+
// Check assignment files
|
|
1437
|
+
<span class="cstat-no" title="statement not covered" > if (fileRecord.assignment?.class) {</span>
|
|
1438
|
+
<span class="cstat-no" title="statement not covered" > const classData = fileRecord.assignment.class;</span>
|
|
1439
|
+
<span class="cstat-no" title="statement not covered" > const isStudent = classData.students.some(student => student.id === user.id);</span>
|
|
1440
|
+
<span class="cstat-no" title="statement not covered" > const isTeacher = classData.teachers.some(teacher => teacher.id === user.id);</span>
|
|
1441
|
+
<span class="cstat-no" title="statement not covered" > if (isStudent || isTeacher) {</span>
|
|
1442
|
+
<span class="cstat-no" title="statement not covered" > hasPermission = true;</span>
|
|
1443
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1444
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1445
|
+
|
|
1446
|
+
<span class="cstat-no" title="statement not covered" > if (!hasPermission && fileRecord.annotations) {</span>
|
|
1447
|
+
<span class="cstat-no" title="statement not covered" > const annotation = fileRecord.annotations;</span>
|
|
1448
|
+
<span class="cstat-no" title="statement not covered" > if (annotation.studentId === user.id) {</span>
|
|
1449
|
+
<span class="cstat-no" title="statement not covered" > hasPermission = true;</span>
|
|
1450
|
+
<span class="cstat-no" title="statement not covered" > } else if (annotation.assignment?.class?.teachers.some(teacher => teacher.id === user.id)) {</span>
|
|
1451
|
+
<span class="cstat-no" title="statement not covered" > hasPermission = true;</span>
|
|
1452
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1453
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1454
|
+
|
|
1455
|
+
// Check submission files (student can access their own submissions, teachers can access all submissions in their class)
|
|
1456
|
+
<span class="cstat-no" title="statement not covered" > if (!hasPermission && fileRecord.submission) {</span>
|
|
1457
|
+
<span class="cstat-no" title="statement not covered" > const submission = fileRecord.submission;</span>
|
|
1458
|
+
<span class="cstat-no" title="statement not covered" > if (submission.studentId === user.id) {</span>
|
|
1459
|
+
<span class="cstat-no" title="statement not covered" > hasPermission = true; // Student accessing their own submission</span>
|
|
1460
|
+
<span class="cstat-no" title="statement not covered" > } else if (submission.assignment?.class?.teachers.some(teacher => teacher.id === user.id)) {</span>
|
|
1461
|
+
<span class="cstat-no" title="statement not covered" > hasPermission = true; // Teacher accessing submission in their class</span>
|
|
1462
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1463
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1464
|
+
|
|
1465
|
+
// Check folder files
|
|
1466
|
+
<span class="cstat-no" title="statement not covered" > if (!hasPermission && fileRecord.folder?.class) {</span>
|
|
1467
|
+
<span class="cstat-no" title="statement not covered" > const classData = fileRecord.folder.class;</span>
|
|
1468
|
+
<span class="cstat-no" title="statement not covered" > const isStudent = classData.students.some(student => student.id === user.id);</span>
|
|
1469
|
+
<span class="cstat-no" title="statement not covered" > const isTeacher = classData.teachers.some(teacher => teacher.id === user.id);</span>
|
|
1470
|
+
<span class="cstat-no" title="statement not covered" > if (isStudent || isTeacher) {</span>
|
|
1471
|
+
<span class="cstat-no" title="statement not covered" > hasPermission = true;</span>
|
|
1472
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1473
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1474
|
+
|
|
1475
|
+
// Check class draft files
|
|
1476
|
+
<span class="cstat-no" title="statement not covered" > if (!hasPermission && fileRecord.classDraft) {</span>
|
|
1477
|
+
<span class="cstat-no" title="statement not covered" > const classData = fileRecord.classDraft;</span>
|
|
1478
|
+
<span class="cstat-no" title="statement not covered" > const isStudent = classData.students.some(student => student.id === user.id);</span>
|
|
1479
|
+
<span class="cstat-no" title="statement not covered" > const isTeacher = classData.teachers.some(teacher => teacher.id === user.id);</span>
|
|
1480
|
+
<span class="cstat-no" title="statement not covered" > if (isStudent || isTeacher) {</span>
|
|
1481
|
+
<span class="cstat-no" title="statement not covered" > hasPermission = true;</span>
|
|
1482
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1483
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1484
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1485
|
+
|
|
1486
|
+
<span class="cstat-no" title="statement not covered" > if (!hasPermission) {</span>
|
|
1487
|
+
<span class="cstat-no" title="statement not covered" > return res.status(403).json({ error: 'Access denied - insufficient permissions' });</span>
|
|
1488
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1489
|
+
|
|
1490
|
+
<span class="cstat-no" title="statement not covered" > const filePath = fileRecord.path;</span>
|
|
1491
|
+
|
|
1492
|
+
// Get file from Google Cloud Storage
|
|
1493
|
+
<span class="cstat-no" title="statement not covered" > const file = bucket.file(filePath);</span>
|
|
1494
|
+
<span class="cstat-no" title="statement not covered" > const [exists] = await file.exists();</span>
|
|
1495
|
+
|
|
1496
|
+
<span class="cstat-no" title="statement not covered" > if (!exists) {</span>
|
|
1497
|
+
<span class="cstat-no" title="statement not covered" > return res.status(404).json({ error: 'File not found in storage', filePath });</span>
|
|
1498
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1499
|
+
|
|
1500
|
+
// Get file metadata
|
|
1501
|
+
<span class="cstat-no" title="statement not covered" > const [metadata] = await file.getMetadata();</span>
|
|
1502
|
+
|
|
1503
|
+
// Set appropriate headers
|
|
1504
|
+
<span class="cstat-no" title="statement not covered" > res.set({</span>
|
|
1505
|
+
<span class="cstat-no" title="statement not covered" > 'Content-Type': metadata.contentType || 'application/octet-stream',</span>
|
|
1506
|
+
<span class="cstat-no" title="statement not covered" > 'Content-Length': metadata.size,</span>
|
|
1507
|
+
<span class="cstat-no" title="statement not covered" > 'Cache-Control': 'public, max-age=31536000', // 1 year cache</span>
|
|
1508
|
+
<span class="cstat-no" title="statement not covered" > 'ETag': metadata.etag,</span>
|
|
1509
|
+
<span class="cstat-no" title="statement not covered" > });</span>
|
|
1510
|
+
|
|
1511
|
+
// Stream file to response
|
|
1512
|
+
<span class="cstat-no" title="statement not covered" > const stream = file.createReadStream();</span>
|
|
1513
|
+
<span class="cstat-no" title="statement not covered" > stream.pipe(res);</span>
|
|
1514
|
+
|
|
1515
|
+
<span class="cstat-no" title="statement not covered" > stream.on('error', (error) => {</span>
|
|
1516
|
+
<span class="cstat-no" title="statement not covered" > logger.error('Error streaming file:', {error});</span>
|
|
1517
|
+
<span class="cstat-no" title="statement not covered" > if (!res.headersSent) {</span>
|
|
1518
|
+
<span class="cstat-no" title="statement not covered" > res.status(500).json({ error: 'Error streaming file' });</span>
|
|
1519
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1520
|
+
<span class="cstat-no" title="statement not covered" > });</span>
|
|
1521
|
+
|
|
1522
|
+
<span class="cstat-no" title="statement not covered" > } catch (error) {</span>
|
|
1523
|
+
<span class="cstat-no" title="statement not covered" > logger.error('Error serving file:', {error});</span>
|
|
1524
|
+
<span class="cstat-no" title="statement not covered" > res.status(500).json({ error: 'Internal server error' });</span>
|
|
1525
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1526
|
+
<span class="cstat-no" title="statement not covered" >});</span>
|
|
1527
|
+
|
|
1528
|
+
<span class="cstat-no" title="statement not covered" >app.use('/trpc/auth.login', authLimiter);</span>
|
|
1529
|
+
<span class="cstat-no" title="statement not covered" >app.use('/trpc/auth.register', authLimiter);</span>
|
|
1530
|
+
|
|
1531
|
+
// File upload endpoint for secure file uploads (supports both POST and PUT)
|
|
1532
|
+
<span class="cstat-no" title="statement not covered" >app.post('/api/upload/:filePath', uploadLimiter, async (req, res) => {</span>
|
|
1533
|
+
<span class="cstat-no" title="statement not covered" > handleFileUpload(req, res);</span>
|
|
1534
|
+
<span class="cstat-no" title="statement not covered" >});</span>
|
|
1535
|
+
|
|
1536
|
+
<span class="cstat-no" title="statement not covered" >app.put('/api/upload/:filePath', uploadLimiter, async (req, res) => {</span>
|
|
1537
|
+
<span class="cstat-no" title="statement not covered" > handleFileUpload(req, res);</span>
|
|
1538
|
+
<span class="cstat-no" title="statement not covered" >});</span>
|
|
1539
|
+
|
|
1540
|
+
<span class="cstat-no" title="statement not covered" >function handleFileUpload(req: any, res: any) {</span>
|
|
1541
|
+
<span class="cstat-no" title="statement not covered" > try {</span>
|
|
1542
|
+
<span class="cstat-no" title="statement not covered" > const filePath = decodeURIComponent(req.params.filePath);</span>
|
|
1543
|
+
|
|
1544
|
+
// Set CORS headers for upload endpoint
|
|
1545
|
+
<span class="cstat-no" title="statement not covered" > const origin = req.headers.origin;</span>
|
|
1546
|
+
<span class="cstat-no" title="statement not covered" > const allowedOrigins = [</span>
|
|
1547
|
+
<span class="cstat-no" title="statement not covered" > 'http://localhost:3000',</span>
|
|
1548
|
+
<span class="cstat-no" title="statement not covered" > 'http://localhost:3001', </span>
|
|
1549
|
+
<span class="cstat-no" title="statement not covered" > 'http://127.0.0.1:3000',</span>
|
|
1550
|
+
<span class="cstat-no" title="statement not covered" > 'http://127.0.0.1:3001',</span>
|
|
1551
|
+
<span class="cstat-no" title="statement not covered" > 'https://www.studious.sh', // Production frontend</span>
|
|
1552
|
+
<span class="cstat-no" title="statement not covered" > 'https://studious.sh', // Production frontend (without www)</span>
|
|
1553
|
+
<span class="cstat-no" title="statement not covered" > env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'</span>
|
|
1554
|
+
<span class="cstat-no" title="statement not covered" > ];</span>
|
|
1555
|
+
|
|
1556
|
+
<span class="cstat-no" title="statement not covered" > if (origin && allowedOrigins.includes(origin)) {</span>
|
|
1557
|
+
<span class="cstat-no" title="statement not covered" > res.header('Access-Control-Allow-Origin', origin);</span>
|
|
1558
|
+
<span class="cstat-no" title="statement not covered" > } else {</span>
|
|
1559
|
+
<span class="cstat-no" title="statement not covered" > res.header('Access-Control-Allow-Origin', 'http://localhost:3000');</span>
|
|
1560
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1561
|
+
|
|
1562
|
+
<span class="cstat-no" title="statement not covered" > res.header('Access-Control-Allow-Credentials', 'true');</span>
|
|
1563
|
+
|
|
1564
|
+
// Get content type from headers
|
|
1565
|
+
<span class="cstat-no" title="statement not covered" > const contentType = req.headers['content-type'] || 'application/octet-stream';</span>
|
|
1566
|
+
|
|
1567
|
+
// Create a new file in the bucket
|
|
1568
|
+
<span class="cstat-no" title="statement not covered" > const file = bucket.file(filePath);</span>
|
|
1569
|
+
|
|
1570
|
+
// Create a write stream to Google Cloud Storage
|
|
1571
|
+
<span class="cstat-no" title="statement not covered" > const writeStream = file.createWriteStream({</span>
|
|
1572
|
+
<span class="cstat-no" title="statement not covered" > metadata: {</span>
|
|
1573
|
+
<span class="cstat-no" title="statement not covered" > contentType,</span>
|
|
1574
|
+
<span class="cstat-no" title="statement not covered" > },</span>
|
|
1575
|
+
<span class="cstat-no" title="statement not covered" > });</span>
|
|
1576
|
+
|
|
1577
|
+
// Handle stream events
|
|
1578
|
+
<span class="cstat-no" title="statement not covered" > writeStream.on('error', (error) => {</span>
|
|
1579
|
+
<span class="cstat-no" title="statement not covered" > logger.error('Error uploading file:', {error});</span>
|
|
1580
|
+
<span class="cstat-no" title="statement not covered" > if (!res.headersSent) {</span>
|
|
1581
|
+
<span class="cstat-no" title="statement not covered" > res.status(500).json({ error: 'Error uploading file' });</span>
|
|
1582
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1583
|
+
<span class="cstat-no" title="statement not covered" > });</span>
|
|
1584
|
+
|
|
1585
|
+
<span class="cstat-no" title="statement not covered" > writeStream.on('finish', () => {</span>
|
|
1586
|
+
<span class="cstat-no" title="statement not covered" > res.status(200).json({ </span>
|
|
1587
|
+
<span class="cstat-no" title="statement not covered" > success: true, </span>
|
|
1588
|
+
<span class="cstat-no" title="statement not covered" > filePath,</span>
|
|
1589
|
+
<span class="cstat-no" title="statement not covered" > message: 'File uploaded successfully' </span>
|
|
1590
|
+
<span class="cstat-no" title="statement not covered" > });</span>
|
|
1591
|
+
<span class="cstat-no" title="statement not covered" > });</span>
|
|
1592
|
+
|
|
1593
|
+
// Pipe the request body to the write stream
|
|
1594
|
+
<span class="cstat-no" title="statement not covered" > req.pipe(writeStream);</span>
|
|
1595
|
+
|
|
1596
|
+
<span class="cstat-no" title="statement not covered" > } catch (error) {</span>
|
|
1597
|
+
<span class="cstat-no" title="statement not covered" > logger.error('Error handling file upload:', {error});</span>
|
|
1598
|
+
<span class="cstat-no" title="statement not covered" > res.status(500).json({ error: 'Internal server error' });</span>
|
|
1599
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1600
|
+
<span class="cstat-no" title="statement not covered" >}</span>
|
|
1601
|
+
|
|
1602
|
+
// Create caller
|
|
1603
|
+
<span class="cstat-no" title="statement not covered" >const createCaller = createCallerFactory(appRouter);</span>
|
|
1604
|
+
|
|
1605
|
+
// Setup tRPC middleware
|
|
1606
|
+
<span class="cstat-no" title="statement not covered" >app.use(</span>
|
|
1607
|
+
<span class="cstat-no" title="statement not covered" > '/trpc',</span>
|
|
1608
|
+
<span class="cstat-no" title="statement not covered" > createExpressMiddleware({</span>
|
|
1609
|
+
<span class="cstat-no" title="statement not covered" > router: appRouter,</span>
|
|
1610
|
+
<span class="cstat-no" title="statement not covered" > createContext: async ({ req, res }: { req: Request; res: Response }) => {</span>
|
|
1611
|
+
<span class="cstat-no" title="statement not covered" > return createTRPCContext({ req, res });</span>
|
|
1612
|
+
<span class="cstat-no" title="statement not covered" > },</span>
|
|
1613
|
+
<span class="cstat-no" title="statement not covered" > })</span>
|
|
1614
|
+
<span class="cstat-no" title="statement not covered" >);</span>
|
|
1615
|
+
|
|
1616
|
+
// IMPORTANT: Sentry error handler must be added AFTER all other middleware and routes
|
|
1617
|
+
// but BEFORE any other error handlers
|
|
1618
|
+
<span class="cstat-no" title="statement not covered" >Sentry.setupExpressErrorHandler(app);</span>
|
|
1619
|
+
|
|
1620
|
+
// app.use(function onError(err, req, res, next) {
|
|
1621
|
+
// // The error id is attached to `res.sentry` to be returned
|
|
1622
|
+
// // and optionally displayed to the user for support.
|
|
1623
|
+
// res.statusCode = 500;
|
|
1624
|
+
// res.end(res.sentry + "\n");
|
|
1625
|
+
// });
|
|
1626
|
+
|
|
1627
|
+
|
|
1628
|
+
<span class="cstat-no" title="statement not covered" >const PORT = env.PORT || 3001;</span>
|
|
1629
|
+
|
|
1630
|
+
<span class="cstat-no" title="statement not covered" >httpServer.listen(PORT, () => {</span>
|
|
1631
|
+
<span class="cstat-no" title="statement not covered" > logger.info(`Server running on port ${PORT}`, { </span>
|
|
1632
|
+
<span class="cstat-no" title="statement not covered" > port: PORT,</span>
|
|
1633
|
+
<span class="cstat-no" title="statement not covered" > services: ['tRPC', 'Socket.IO']</span>
|
|
1634
|
+
<span class="cstat-no" title="statement not covered" > });</span>
|
|
1635
|
+
<span class="cstat-no" title="statement not covered" >}); </span>
|
|
1636
|
+
|
|
1637
|
+
// log all env variables
|
|
1638
|
+
<span class="cstat-no" title="statement not covered" >logger.info('Configurations', {</span>
|
|
1639
|
+
<span class="cstat-no" title="statement not covered" > NODE_ENV: env.NODE_ENV,</span>
|
|
1640
|
+
<span class="cstat-no" title="statement not covered" > PORT: env.PORT,</span>
|
|
1641
|
+
<span class="cstat-no" title="statement not covered" > NEXT_PUBLIC_APP_URL: env.NEXT_PUBLIC_APP_URL,</span>
|
|
1642
|
+
<span class="cstat-no" title="statement not covered" > LOG_MODE: env.LOG_MODE,</span>
|
|
1643
|
+
<span class="cstat-no" title="statement not covered" >});</span>
|
|
1644
|
+
|
|
1645
|
+
// Log CORS configuration
|
|
1646
|
+
<span class="cstat-no" title="statement not covered" >logger.info('CORS Configuration', {</span>
|
|
1647
|
+
<span class="cstat-no" title="statement not covered" > allowedOrigins: [</span>
|
|
1648
|
+
<span class="cstat-no" title="statement not covered" > 'http://localhost:3000',</span>
|
|
1649
|
+
<span class="cstat-no" title="statement not covered" > 'http://localhost:3001', </span>
|
|
1650
|
+
<span class="cstat-no" title="statement not covered" > 'http://127.0.0.1:3000',</span>
|
|
1651
|
+
<span class="cstat-no" title="statement not covered" > 'http://127.0.0.1:3001',</span>
|
|
1652
|
+
<span class="cstat-no" title="statement not covered" > env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'</span>
|
|
1653
|
+
<span class="cstat-no" title="statement not covered" > ]</span>
|
|
1654
|
+
<span class="cstat-no" title="statement not covered" >});</span>
|
|
1655
|
+
|
|
1656
|
+
<span class="cstat-no" title="statement not covered" >const gracefulShutdown = (signal: string) => {</span>
|
|
1657
|
+
<span class="cstat-no" title="statement not covered" > logger.info(`Received ${signal}, shutting down gracefully`);</span>
|
|
1658
|
+
|
|
1659
|
+
<span class="cstat-no" title="statement not covered" > httpServer.close(() => {</span>
|
|
1660
|
+
<span class="cstat-no" title="statement not covered" > logger.info('HTTP server closed');</span>
|
|
1661
|
+
|
|
1662
|
+
<span class="cstat-no" title="statement not covered" > io.close(() => {</span>
|
|
1663
|
+
<span class="cstat-no" title="statement not covered" > logger.info('Socket.IO server closed');</span>
|
|
1664
|
+
|
|
1665
|
+
<span class="cstat-no" title="statement not covered" > prisma.$disconnect().then(() => {</span>
|
|
1666
|
+
<span class="cstat-no" title="statement not covered" > logger.info('Database connections closed');</span>
|
|
1667
|
+
<span class="cstat-no" title="statement not covered" > process.exit(0);</span>
|
|
1668
|
+
<span class="cstat-no" title="statement not covered" > }).catch((err) => {</span>
|
|
1669
|
+
<span class="cstat-no" title="statement not covered" > logger.error('Error disconnecting from database', { error: err });</span>
|
|
1670
|
+
<span class="cstat-no" title="statement not covered" > process.exit(1);</span>
|
|
1671
|
+
<span class="cstat-no" title="statement not covered" > });</span>
|
|
1672
|
+
<span class="cstat-no" title="statement not covered" > });</span>
|
|
1673
|
+
<span class="cstat-no" title="statement not covered" > });</span>
|
|
1674
|
+
|
|
1675
|
+
// Force shutdown after 10 seconds
|
|
1676
|
+
<span class="cstat-no" title="statement not covered" > setTimeout(() => {</span>
|
|
1677
|
+
<span class="cstat-no" title="statement not covered" > logger.error('Forced shutdown after timeout');</span>
|
|
1678
|
+
<span class="cstat-no" title="statement not covered" > process.exit(1);</span>
|
|
1679
|
+
<span class="cstat-no" title="statement not covered" > }, 10000);</span>
|
|
1680
|
+
<span class="cstat-no" title="statement not covered" >};</span>
|
|
1681
|
+
|
|
1682
|
+
<span class="cstat-no" title="statement not covered" >process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));</span>
|
|
1683
|
+
<span class="cstat-no" title="statement not covered" >process.on('SIGINT', () => gracefulShutdown('SIGINT'));</span></pre></td></tr></table></pre>
|
|
1684
|
+
|
|
1685
|
+
<div class='push'></div><!-- for sticky footer -->
|
|
1686
|
+
</div><!-- /wrapper -->
|
|
1687
|
+
<div class='footer quiet pad2 space-top1 center small'>
|
|
1688
|
+
Code coverage generated by
|
|
1689
|
+
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
1690
|
+
at 2025-11-22T10:42:40.796Z
|
|
1691
|
+
</div>
|
|
1692
|
+
<script src="../../prettify.js"></script>
|
|
1693
|
+
<script>
|
|
1694
|
+
window.onload = function () {
|
|
1695
|
+
prettyPrint();
|
|
1696
|
+
};
|
|
1697
|
+
</script>
|
|
1698
|
+
<script src="../../sorter.js"></script>
|
|
1699
|
+
<script src="../../block-navigation.js"></script>
|
|
1700
|
+
</body>
|
|
1701
|
+
</html>
|
|
1702
|
+
|