@nocios/crudify-components 2.0.36 → 2.0.38
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/coverage/components/CrudiaAutoGenerate.tsx.html +583 -0
- package/coverage/components/CrudiaFileField/CrudiaFileField.tsx.html +1276 -0
- package/coverage/components/CrudiaFileField/components/DeleteConfirmationDialog.tsx.html +355 -0
- package/coverage/components/CrudiaFileField/components/DropZone.tsx.html +433 -0
- package/coverage/components/CrudiaFileField/components/FileItemRow.tsx.html +751 -0
- package/coverage/components/CrudiaFileField/components/FileThumbnail.tsx.html +1195 -0
- package/coverage/components/CrudiaFileField/components/index.html +176 -0
- package/coverage/components/CrudiaFileField/components/index.ts.html +115 -0
- package/coverage/components/CrudiaFileField/hooks/index.html +146 -0
- package/coverage/components/CrudiaFileField/hooks/index.ts.html +112 -0
- package/coverage/components/CrudiaFileField/hooks/useDeleteConfirmation.ts.html +421 -0
- package/coverage/components/CrudiaFileField/hooks/useDragDrop.ts.html +403 -0
- package/coverage/components/CrudiaFileField/index.html +131 -0
- package/coverage/components/CrudiaFileField/index.ts.html +112 -0
- package/coverage/components/CrudiaFileField/utils/formatters.ts.html +163 -0
- package/coverage/components/CrudiaFileField/utils/icons.tsx.html +253 -0
- package/coverage/components/CrudiaFileField/utils/index.html +131 -0
- package/coverage/components/CrudiaMarkdownField.tsx.html +619 -0
- package/coverage/components/CrudifyLogin/Forms/CheckCodeForm.tsx.html +586 -0
- package/coverage/components/CrudifyLogin/Forms/ForgotPasswordForm.tsx.html +694 -0
- package/coverage/components/CrudifyLogin/Forms/LoginForm.tsx.html +835 -0
- package/coverage/components/CrudifyLogin/Forms/ResetPasswordForm.tsx.html +1180 -0
- package/coverage/components/CrudifyLogin/Forms/components/CodeInput.tsx.html +283 -0
- package/coverage/components/CrudifyLogin/Forms/components/FormAlert.tsx.html +202 -0
- package/coverage/components/CrudifyLogin/Forms/components/PasswordInput.tsx.html +340 -0
- package/coverage/components/CrudifyLogin/Forms/components/index.html +161 -0
- package/coverage/components/CrudifyLogin/Forms/components/index.ts.html +106 -0
- package/coverage/components/CrudifyLogin/Forms/index.html +161 -0
- package/coverage/components/CrudifyLogin/Forms/utils/errorTranslation.ts.html +268 -0
- package/coverage/components/CrudifyLogin/Forms/utils/index.html +161 -0
- package/coverage/components/CrudifyLogin/Forms/utils/index.ts.html +106 -0
- package/coverage/components/CrudifyLogin/Forms/utils/paramUtils.ts.html +478 -0
- package/coverage/components/CrudifyLogin/Forms/utils/validation.ts.html +289 -0
- package/coverage/components/CrudifyLogin/components/CrudifyInitializer.tsx.html +262 -0
- package/coverage/components/CrudifyLogin/components/index.html +116 -0
- package/coverage/components/CrudifyLogin/context/CrudifyProvider.tsx.html +382 -0
- package/coverage/components/CrudifyLogin/context/I18nProvider.tsx.html +397 -0
- package/coverage/components/CrudifyLogin/context/LoginStateProvider.tsx.html +1249 -0
- package/coverage/components/CrudifyLogin/context/index.html +146 -0
- package/coverage/components/CrudifyLogin/hooks/index.html +116 -0
- package/coverage/components/CrudifyLogin/hooks/useTranslationsFromUrl.ts.html +292 -0
- package/coverage/components/CrudifyLogin/index.html +116 -0
- package/coverage/components/CrudifyLogin/index.tsx.html +475 -0
- package/coverage/components/GlobalNotificationProvider.tsx.html +781 -0
- package/coverage/components/LoginComponent.tsx.html +727 -0
- package/coverage/components/PasswordRequirements/index.html +116 -0
- package/coverage/components/PasswordRequirements/index.tsx.html +226 -0
- package/coverage/components/PublicPolicies/FieldSelector/FieldSelector.tsx.html +982 -0
- package/coverage/components/PublicPolicies/FieldSelector/index.html +131 -0
- package/coverage/components/PublicPolicies/FieldSelector/index.ts.html +85 -0
- package/coverage/components/PublicPolicies/Policies.tsx.html +610 -0
- package/coverage/components/PublicPolicies/PolicyItem/PolicyItem.tsx.html +856 -0
- package/coverage/components/PublicPolicies/PolicyItem/index.html +131 -0
- package/coverage/components/PublicPolicies/PolicyItem/index.ts.html +85 -0
- package/coverage/components/PublicPolicies/constants.ts.html +127 -0
- package/coverage/components/PublicPolicies/index.html +131 -0
- package/coverage/components/SessionTimeIndicator/index.html +116 -0
- package/coverage/components/SessionTimeIndicator/index.tsx.html +505 -0
- package/coverage/components/UserProfile/UserProfileDisplay.tsx.html +826 -0
- package/coverage/components/UserProfile/index.html +131 -0
- package/coverage/components/UserProfile/index.ts.html +85 -0
- package/coverage/components/index.html +176 -0
- package/coverage/components/index.ts.html +160 -0
- package/coverage/core/CrossTabSyncManager.ts.html +814 -0
- package/coverage/core/CrudifyInitializationManager.ts.html +1132 -0
- package/coverage/core/SessionManager.ts.html +2764 -0
- package/coverage/core/index.html +146 -0
- package/coverage/coverage-final.json +52 -85
- package/coverage/hooks/index.html +131 -0
- package/coverage/hooks/useAutoGenerate.ts.html +562 -0
- package/coverage/hooks/useFileUpload/index.html +131 -0
- package/coverage/hooks/useFileUpload/index.ts.html +112 -0
- package/coverage/hooks/useFileUpload/services/index.html +116 -0
- package/coverage/hooks/useFileUpload/services/uploadService.ts.html +610 -0
- package/coverage/hooks/useFileUpload/useFileUpload.ts.html +1870 -0
- package/coverage/hooks/useFileUpload/utils/fileUtils.ts.html +271 -0
- package/coverage/hooks/useFileUpload/utils/index.html +146 -0
- package/coverage/hooks/useFileUpload/utils/mimeTypes.ts.html +235 -0
- package/coverage/hooks/useFileUpload/utils/validation.ts.html +379 -0
- package/coverage/hooks/useSession/constants.ts.html +217 -0
- package/coverage/hooks/useSession/hooks/index.html +176 -0
- package/coverage/hooks/useSession/hooks/useAuthEventSubscriber.ts.html +331 -0
- package/coverage/hooks/useSession/hooks/useCrossTabSync.ts.html +433 -0
- package/coverage/hooks/useSession/hooks/useSessionActions.ts.html +664 -0
- package/coverage/hooks/useSession/hooks/useSessionState.ts.html +295 -0
- package/coverage/hooks/useSession/hooks/useTokenRefreshScheduler.ts.html +490 -0
- package/coverage/hooks/useSession/index.html +161 -0
- package/coverage/hooks/useSession/index.ts.html +127 -0
- package/coverage/hooks/useSession/types.ts.html +427 -0
- package/coverage/hooks/useSession/useSession.ts.html +526 -0
- package/coverage/hooks/useSession/utils/index.html +131 -0
- package/coverage/hooks/useSession/utils/initializeSession.ts.html +424 -0
- package/coverage/hooks/useSession/utils/tokenUtils.ts.html +280 -0
- package/coverage/hooks/useUserProfile.ts.html +658 -0
- package/coverage/index.html +237 -357
- package/coverage/providers/SessionProvider.tsx.html +1150 -0
- package/coverage/providers/TranslationsProvider.tsx.html +1450 -0
- package/coverage/providers/index.html +131 -0
- package/coverage/services/credentialsEventBus.ts.html +310 -0
- package/coverage/services/index.html +131 -0
- package/coverage/services/translationService.ts.html +1318 -0
- package/coverage/translations/critical.ts.html +1195 -0
- package/coverage/translations/index.html +116 -0
- package/coverage/types/index.html +116 -0
- package/coverage/types/password.ts.html +178 -0
- package/coverage/utils/authEventBus.ts.html +454 -0
- package/coverage/utils/configResolver.ts.html +460 -0
- package/coverage/utils/cookieSync.ts.html +580 -0
- package/coverage/utils/errorHandler.ts.html +1264 -0
- package/coverage/utils/errorTranslation.ts.html +862 -0
- package/coverage/utils/index.html +296 -0
- package/coverage/utils/jwtUtils.ts.html +301 -0
- package/coverage/utils/logger.ts.html +901 -0
- package/coverage/utils/navigationTracker.ts.html +565 -0
- package/coverage/utils/passwordValidation.ts.html +259 -0
- package/coverage/utils/redirectSecurity.ts.html +715 -0
- package/coverage/utils/tenantConfig.ts.html +700 -0
- package/coverage/utils/tokenStorage.ts.html +1768 -0
- package/coverage/utils/webCrypto.ts.html +472 -0
- package/dist/{CrudiaMarkdownField-Bxl08sRG.d.mts → CrudiaMarkdownField-BvJn2GL8.d.mts} +5 -0
- package/dist/{CrudiaMarkdownField-DUJNOOzP.d.ts → CrudiaMarkdownField-CggOpcBM.d.ts} +5 -0
- package/dist/chunk-SYHNHKFA.mjs +1 -0
- package/dist/chunk-W4ZYKPOK.js +1 -0
- package/dist/components.d.mts +1 -1
- package/dist/components.d.ts +1 -1
- package/dist/components.js +1 -1
- package/dist/components.mjs +1 -1
- package/dist/index.d.mts +6 -2
- package/dist/index.d.ts +6 -2
- package/dist/index.js +2 -2
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
- package/dist/chunk-QFACMV2I.mjs +0 -1
- package/dist/chunk-QZH3KSJZ.js +0 -1
|
@@ -0,0 +1,1870 @@
|
|
|
1
|
+
|
|
2
|
+
<!doctype html>
|
|
3
|
+
<html lang="en">
|
|
4
|
+
|
|
5
|
+
<head>
|
|
6
|
+
<title>Code coverage report for hooks/useFileUpload/useFileUpload.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">hooks/useFileUpload</a> useFileUpload.ts</h1>
|
|
23
|
+
<div class='clearfix'>
|
|
24
|
+
|
|
25
|
+
<div class='fl pad1y space-right2'>
|
|
26
|
+
<span class="strong">79.32% </span>
|
|
27
|
+
<span class="quiet">Statements</span>
|
|
28
|
+
<span class='fraction'>472/595</span>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
<div class='fl pad1y space-right2'>
|
|
33
|
+
<span class="strong">76.38% </span>
|
|
34
|
+
<span class="quiet">Branches</span>
|
|
35
|
+
<span class='fraction'>55/72</span>
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
<div class='fl pad1y space-right2'>
|
|
40
|
+
<span class="strong">50% </span>
|
|
41
|
+
<span class="quiet">Functions</span>
|
|
42
|
+
<span class='fraction'>1/2</span>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
<div class='fl pad1y space-right2'>
|
|
47
|
+
<span class="strong">79.32% </span>
|
|
48
|
+
<span class="quiet">Lines</span>
|
|
49
|
+
<span class='fraction'>472/595</span>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
<p class="quiet">
|
|
55
|
+
Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block.
|
|
56
|
+
</p>
|
|
57
|
+
<template id="filterTemplate">
|
|
58
|
+
<div class="quiet">
|
|
59
|
+
Filter:
|
|
60
|
+
<input type="search" id="fileSearch">
|
|
61
|
+
</div>
|
|
62
|
+
</template>
|
|
63
|
+
</div>
|
|
64
|
+
<div class='status-line medium'></div>
|
|
65
|
+
<pre><table class="coverage">
|
|
66
|
+
<tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
|
|
67
|
+
<a name='L2'></a><a href='#L2'>2</a>
|
|
68
|
+
<a name='L3'></a><a href='#L3'>3</a>
|
|
69
|
+
<a name='L4'></a><a href='#L4'>4</a>
|
|
70
|
+
<a name='L5'></a><a href='#L5'>5</a>
|
|
71
|
+
<a name='L6'></a><a href='#L6'>6</a>
|
|
72
|
+
<a name='L7'></a><a href='#L7'>7</a>
|
|
73
|
+
<a name='L8'></a><a href='#L8'>8</a>
|
|
74
|
+
<a name='L9'></a><a href='#L9'>9</a>
|
|
75
|
+
<a name='L10'></a><a href='#L10'>10</a>
|
|
76
|
+
<a name='L11'></a><a href='#L11'>11</a>
|
|
77
|
+
<a name='L12'></a><a href='#L12'>12</a>
|
|
78
|
+
<a name='L13'></a><a href='#L13'>13</a>
|
|
79
|
+
<a name='L14'></a><a href='#L14'>14</a>
|
|
80
|
+
<a name='L15'></a><a href='#L15'>15</a>
|
|
81
|
+
<a name='L16'></a><a href='#L16'>16</a>
|
|
82
|
+
<a name='L17'></a><a href='#L17'>17</a>
|
|
83
|
+
<a name='L18'></a><a href='#L18'>18</a>
|
|
84
|
+
<a name='L19'></a><a href='#L19'>19</a>
|
|
85
|
+
<a name='L20'></a><a href='#L20'>20</a>
|
|
86
|
+
<a name='L21'></a><a href='#L21'>21</a>
|
|
87
|
+
<a name='L22'></a><a href='#L22'>22</a>
|
|
88
|
+
<a name='L23'></a><a href='#L23'>23</a>
|
|
89
|
+
<a name='L24'></a><a href='#L24'>24</a>
|
|
90
|
+
<a name='L25'></a><a href='#L25'>25</a>
|
|
91
|
+
<a name='L26'></a><a href='#L26'>26</a>
|
|
92
|
+
<a name='L27'></a><a href='#L27'>27</a>
|
|
93
|
+
<a name='L28'></a><a href='#L28'>28</a>
|
|
94
|
+
<a name='L29'></a><a href='#L29'>29</a>
|
|
95
|
+
<a name='L30'></a><a href='#L30'>30</a>
|
|
96
|
+
<a name='L31'></a><a href='#L31'>31</a>
|
|
97
|
+
<a name='L32'></a><a href='#L32'>32</a>
|
|
98
|
+
<a name='L33'></a><a href='#L33'>33</a>
|
|
99
|
+
<a name='L34'></a><a href='#L34'>34</a>
|
|
100
|
+
<a name='L35'></a><a href='#L35'>35</a>
|
|
101
|
+
<a name='L36'></a><a href='#L36'>36</a>
|
|
102
|
+
<a name='L37'></a><a href='#L37'>37</a>
|
|
103
|
+
<a name='L38'></a><a href='#L38'>38</a>
|
|
104
|
+
<a name='L39'></a><a href='#L39'>39</a>
|
|
105
|
+
<a name='L40'></a><a href='#L40'>40</a>
|
|
106
|
+
<a name='L41'></a><a href='#L41'>41</a>
|
|
107
|
+
<a name='L42'></a><a href='#L42'>42</a>
|
|
108
|
+
<a name='L43'></a><a href='#L43'>43</a>
|
|
109
|
+
<a name='L44'></a><a href='#L44'>44</a>
|
|
110
|
+
<a name='L45'></a><a href='#L45'>45</a>
|
|
111
|
+
<a name='L46'></a><a href='#L46'>46</a>
|
|
112
|
+
<a name='L47'></a><a href='#L47'>47</a>
|
|
113
|
+
<a name='L48'></a><a href='#L48'>48</a>
|
|
114
|
+
<a name='L49'></a><a href='#L49'>49</a>
|
|
115
|
+
<a name='L50'></a><a href='#L50'>50</a>
|
|
116
|
+
<a name='L51'></a><a href='#L51'>51</a>
|
|
117
|
+
<a name='L52'></a><a href='#L52'>52</a>
|
|
118
|
+
<a name='L53'></a><a href='#L53'>53</a>
|
|
119
|
+
<a name='L54'></a><a href='#L54'>54</a>
|
|
120
|
+
<a name='L55'></a><a href='#L55'>55</a>
|
|
121
|
+
<a name='L56'></a><a href='#L56'>56</a>
|
|
122
|
+
<a name='L57'></a><a href='#L57'>57</a>
|
|
123
|
+
<a name='L58'></a><a href='#L58'>58</a>
|
|
124
|
+
<a name='L59'></a><a href='#L59'>59</a>
|
|
125
|
+
<a name='L60'></a><a href='#L60'>60</a>
|
|
126
|
+
<a name='L61'></a><a href='#L61'>61</a>
|
|
127
|
+
<a name='L62'></a><a href='#L62'>62</a>
|
|
128
|
+
<a name='L63'></a><a href='#L63'>63</a>
|
|
129
|
+
<a name='L64'></a><a href='#L64'>64</a>
|
|
130
|
+
<a name='L65'></a><a href='#L65'>65</a>
|
|
131
|
+
<a name='L66'></a><a href='#L66'>66</a>
|
|
132
|
+
<a name='L67'></a><a href='#L67'>67</a>
|
|
133
|
+
<a name='L68'></a><a href='#L68'>68</a>
|
|
134
|
+
<a name='L69'></a><a href='#L69'>69</a>
|
|
135
|
+
<a name='L70'></a><a href='#L70'>70</a>
|
|
136
|
+
<a name='L71'></a><a href='#L71'>71</a>
|
|
137
|
+
<a name='L72'></a><a href='#L72'>72</a>
|
|
138
|
+
<a name='L73'></a><a href='#L73'>73</a>
|
|
139
|
+
<a name='L74'></a><a href='#L74'>74</a>
|
|
140
|
+
<a name='L75'></a><a href='#L75'>75</a>
|
|
141
|
+
<a name='L76'></a><a href='#L76'>76</a>
|
|
142
|
+
<a name='L77'></a><a href='#L77'>77</a>
|
|
143
|
+
<a name='L78'></a><a href='#L78'>78</a>
|
|
144
|
+
<a name='L79'></a><a href='#L79'>79</a>
|
|
145
|
+
<a name='L80'></a><a href='#L80'>80</a>
|
|
146
|
+
<a name='L81'></a><a href='#L81'>81</a>
|
|
147
|
+
<a name='L82'></a><a href='#L82'>82</a>
|
|
148
|
+
<a name='L83'></a><a href='#L83'>83</a>
|
|
149
|
+
<a name='L84'></a><a href='#L84'>84</a>
|
|
150
|
+
<a name='L85'></a><a href='#L85'>85</a>
|
|
151
|
+
<a name='L86'></a><a href='#L86'>86</a>
|
|
152
|
+
<a name='L87'></a><a href='#L87'>87</a>
|
|
153
|
+
<a name='L88'></a><a href='#L88'>88</a>
|
|
154
|
+
<a name='L89'></a><a href='#L89'>89</a>
|
|
155
|
+
<a name='L90'></a><a href='#L90'>90</a>
|
|
156
|
+
<a name='L91'></a><a href='#L91'>91</a>
|
|
157
|
+
<a name='L92'></a><a href='#L92'>92</a>
|
|
158
|
+
<a name='L93'></a><a href='#L93'>93</a>
|
|
159
|
+
<a name='L94'></a><a href='#L94'>94</a>
|
|
160
|
+
<a name='L95'></a><a href='#L95'>95</a>
|
|
161
|
+
<a name='L96'></a><a href='#L96'>96</a>
|
|
162
|
+
<a name='L97'></a><a href='#L97'>97</a>
|
|
163
|
+
<a name='L98'></a><a href='#L98'>98</a>
|
|
164
|
+
<a name='L99'></a><a href='#L99'>99</a>
|
|
165
|
+
<a name='L100'></a><a href='#L100'>100</a>
|
|
166
|
+
<a name='L101'></a><a href='#L101'>101</a>
|
|
167
|
+
<a name='L102'></a><a href='#L102'>102</a>
|
|
168
|
+
<a name='L103'></a><a href='#L103'>103</a>
|
|
169
|
+
<a name='L104'></a><a href='#L104'>104</a>
|
|
170
|
+
<a name='L105'></a><a href='#L105'>105</a>
|
|
171
|
+
<a name='L106'></a><a href='#L106'>106</a>
|
|
172
|
+
<a name='L107'></a><a href='#L107'>107</a>
|
|
173
|
+
<a name='L108'></a><a href='#L108'>108</a>
|
|
174
|
+
<a name='L109'></a><a href='#L109'>109</a>
|
|
175
|
+
<a name='L110'></a><a href='#L110'>110</a>
|
|
176
|
+
<a name='L111'></a><a href='#L111'>111</a>
|
|
177
|
+
<a name='L112'></a><a href='#L112'>112</a>
|
|
178
|
+
<a name='L113'></a><a href='#L113'>113</a>
|
|
179
|
+
<a name='L114'></a><a href='#L114'>114</a>
|
|
180
|
+
<a name='L115'></a><a href='#L115'>115</a>
|
|
181
|
+
<a name='L116'></a><a href='#L116'>116</a>
|
|
182
|
+
<a name='L117'></a><a href='#L117'>117</a>
|
|
183
|
+
<a name='L118'></a><a href='#L118'>118</a>
|
|
184
|
+
<a name='L119'></a><a href='#L119'>119</a>
|
|
185
|
+
<a name='L120'></a><a href='#L120'>120</a>
|
|
186
|
+
<a name='L121'></a><a href='#L121'>121</a>
|
|
187
|
+
<a name='L122'></a><a href='#L122'>122</a>
|
|
188
|
+
<a name='L123'></a><a href='#L123'>123</a>
|
|
189
|
+
<a name='L124'></a><a href='#L124'>124</a>
|
|
190
|
+
<a name='L125'></a><a href='#L125'>125</a>
|
|
191
|
+
<a name='L126'></a><a href='#L126'>126</a>
|
|
192
|
+
<a name='L127'></a><a href='#L127'>127</a>
|
|
193
|
+
<a name='L128'></a><a href='#L128'>128</a>
|
|
194
|
+
<a name='L129'></a><a href='#L129'>129</a>
|
|
195
|
+
<a name='L130'></a><a href='#L130'>130</a>
|
|
196
|
+
<a name='L131'></a><a href='#L131'>131</a>
|
|
197
|
+
<a name='L132'></a><a href='#L132'>132</a>
|
|
198
|
+
<a name='L133'></a><a href='#L133'>133</a>
|
|
199
|
+
<a name='L134'></a><a href='#L134'>134</a>
|
|
200
|
+
<a name='L135'></a><a href='#L135'>135</a>
|
|
201
|
+
<a name='L136'></a><a href='#L136'>136</a>
|
|
202
|
+
<a name='L137'></a><a href='#L137'>137</a>
|
|
203
|
+
<a name='L138'></a><a href='#L138'>138</a>
|
|
204
|
+
<a name='L139'></a><a href='#L139'>139</a>
|
|
205
|
+
<a name='L140'></a><a href='#L140'>140</a>
|
|
206
|
+
<a name='L141'></a><a href='#L141'>141</a>
|
|
207
|
+
<a name='L142'></a><a href='#L142'>142</a>
|
|
208
|
+
<a name='L143'></a><a href='#L143'>143</a>
|
|
209
|
+
<a name='L144'></a><a href='#L144'>144</a>
|
|
210
|
+
<a name='L145'></a><a href='#L145'>145</a>
|
|
211
|
+
<a name='L146'></a><a href='#L146'>146</a>
|
|
212
|
+
<a name='L147'></a><a href='#L147'>147</a>
|
|
213
|
+
<a name='L148'></a><a href='#L148'>148</a>
|
|
214
|
+
<a name='L149'></a><a href='#L149'>149</a>
|
|
215
|
+
<a name='L150'></a><a href='#L150'>150</a>
|
|
216
|
+
<a name='L151'></a><a href='#L151'>151</a>
|
|
217
|
+
<a name='L152'></a><a href='#L152'>152</a>
|
|
218
|
+
<a name='L153'></a><a href='#L153'>153</a>
|
|
219
|
+
<a name='L154'></a><a href='#L154'>154</a>
|
|
220
|
+
<a name='L155'></a><a href='#L155'>155</a>
|
|
221
|
+
<a name='L156'></a><a href='#L156'>156</a>
|
|
222
|
+
<a name='L157'></a><a href='#L157'>157</a>
|
|
223
|
+
<a name='L158'></a><a href='#L158'>158</a>
|
|
224
|
+
<a name='L159'></a><a href='#L159'>159</a>
|
|
225
|
+
<a name='L160'></a><a href='#L160'>160</a>
|
|
226
|
+
<a name='L161'></a><a href='#L161'>161</a>
|
|
227
|
+
<a name='L162'></a><a href='#L162'>162</a>
|
|
228
|
+
<a name='L163'></a><a href='#L163'>163</a>
|
|
229
|
+
<a name='L164'></a><a href='#L164'>164</a>
|
|
230
|
+
<a name='L165'></a><a href='#L165'>165</a>
|
|
231
|
+
<a name='L166'></a><a href='#L166'>166</a>
|
|
232
|
+
<a name='L167'></a><a href='#L167'>167</a>
|
|
233
|
+
<a name='L168'></a><a href='#L168'>168</a>
|
|
234
|
+
<a name='L169'></a><a href='#L169'>169</a>
|
|
235
|
+
<a name='L170'></a><a href='#L170'>170</a>
|
|
236
|
+
<a name='L171'></a><a href='#L171'>171</a>
|
|
237
|
+
<a name='L172'></a><a href='#L172'>172</a>
|
|
238
|
+
<a name='L173'></a><a href='#L173'>173</a>
|
|
239
|
+
<a name='L174'></a><a href='#L174'>174</a>
|
|
240
|
+
<a name='L175'></a><a href='#L175'>175</a>
|
|
241
|
+
<a name='L176'></a><a href='#L176'>176</a>
|
|
242
|
+
<a name='L177'></a><a href='#L177'>177</a>
|
|
243
|
+
<a name='L178'></a><a href='#L178'>178</a>
|
|
244
|
+
<a name='L179'></a><a href='#L179'>179</a>
|
|
245
|
+
<a name='L180'></a><a href='#L180'>180</a>
|
|
246
|
+
<a name='L181'></a><a href='#L181'>181</a>
|
|
247
|
+
<a name='L182'></a><a href='#L182'>182</a>
|
|
248
|
+
<a name='L183'></a><a href='#L183'>183</a>
|
|
249
|
+
<a name='L184'></a><a href='#L184'>184</a>
|
|
250
|
+
<a name='L185'></a><a href='#L185'>185</a>
|
|
251
|
+
<a name='L186'></a><a href='#L186'>186</a>
|
|
252
|
+
<a name='L187'></a><a href='#L187'>187</a>
|
|
253
|
+
<a name='L188'></a><a href='#L188'>188</a>
|
|
254
|
+
<a name='L189'></a><a href='#L189'>189</a>
|
|
255
|
+
<a name='L190'></a><a href='#L190'>190</a>
|
|
256
|
+
<a name='L191'></a><a href='#L191'>191</a>
|
|
257
|
+
<a name='L192'></a><a href='#L192'>192</a>
|
|
258
|
+
<a name='L193'></a><a href='#L193'>193</a>
|
|
259
|
+
<a name='L194'></a><a href='#L194'>194</a>
|
|
260
|
+
<a name='L195'></a><a href='#L195'>195</a>
|
|
261
|
+
<a name='L196'></a><a href='#L196'>196</a>
|
|
262
|
+
<a name='L197'></a><a href='#L197'>197</a>
|
|
263
|
+
<a name='L198'></a><a href='#L198'>198</a>
|
|
264
|
+
<a name='L199'></a><a href='#L199'>199</a>
|
|
265
|
+
<a name='L200'></a><a href='#L200'>200</a>
|
|
266
|
+
<a name='L201'></a><a href='#L201'>201</a>
|
|
267
|
+
<a name='L202'></a><a href='#L202'>202</a>
|
|
268
|
+
<a name='L203'></a><a href='#L203'>203</a>
|
|
269
|
+
<a name='L204'></a><a href='#L204'>204</a>
|
|
270
|
+
<a name='L205'></a><a href='#L205'>205</a>
|
|
271
|
+
<a name='L206'></a><a href='#L206'>206</a>
|
|
272
|
+
<a name='L207'></a><a href='#L207'>207</a>
|
|
273
|
+
<a name='L208'></a><a href='#L208'>208</a>
|
|
274
|
+
<a name='L209'></a><a href='#L209'>209</a>
|
|
275
|
+
<a name='L210'></a><a href='#L210'>210</a>
|
|
276
|
+
<a name='L211'></a><a href='#L211'>211</a>
|
|
277
|
+
<a name='L212'></a><a href='#L212'>212</a>
|
|
278
|
+
<a name='L213'></a><a href='#L213'>213</a>
|
|
279
|
+
<a name='L214'></a><a href='#L214'>214</a>
|
|
280
|
+
<a name='L215'></a><a href='#L215'>215</a>
|
|
281
|
+
<a name='L216'></a><a href='#L216'>216</a>
|
|
282
|
+
<a name='L217'></a><a href='#L217'>217</a>
|
|
283
|
+
<a name='L218'></a><a href='#L218'>218</a>
|
|
284
|
+
<a name='L219'></a><a href='#L219'>219</a>
|
|
285
|
+
<a name='L220'></a><a href='#L220'>220</a>
|
|
286
|
+
<a name='L221'></a><a href='#L221'>221</a>
|
|
287
|
+
<a name='L222'></a><a href='#L222'>222</a>
|
|
288
|
+
<a name='L223'></a><a href='#L223'>223</a>
|
|
289
|
+
<a name='L224'></a><a href='#L224'>224</a>
|
|
290
|
+
<a name='L225'></a><a href='#L225'>225</a>
|
|
291
|
+
<a name='L226'></a><a href='#L226'>226</a>
|
|
292
|
+
<a name='L227'></a><a href='#L227'>227</a>
|
|
293
|
+
<a name='L228'></a><a href='#L228'>228</a>
|
|
294
|
+
<a name='L229'></a><a href='#L229'>229</a>
|
|
295
|
+
<a name='L230'></a><a href='#L230'>230</a>
|
|
296
|
+
<a name='L231'></a><a href='#L231'>231</a>
|
|
297
|
+
<a name='L232'></a><a href='#L232'>232</a>
|
|
298
|
+
<a name='L233'></a><a href='#L233'>233</a>
|
|
299
|
+
<a name='L234'></a><a href='#L234'>234</a>
|
|
300
|
+
<a name='L235'></a><a href='#L235'>235</a>
|
|
301
|
+
<a name='L236'></a><a href='#L236'>236</a>
|
|
302
|
+
<a name='L237'></a><a href='#L237'>237</a>
|
|
303
|
+
<a name='L238'></a><a href='#L238'>238</a>
|
|
304
|
+
<a name='L239'></a><a href='#L239'>239</a>
|
|
305
|
+
<a name='L240'></a><a href='#L240'>240</a>
|
|
306
|
+
<a name='L241'></a><a href='#L241'>241</a>
|
|
307
|
+
<a name='L242'></a><a href='#L242'>242</a>
|
|
308
|
+
<a name='L243'></a><a href='#L243'>243</a>
|
|
309
|
+
<a name='L244'></a><a href='#L244'>244</a>
|
|
310
|
+
<a name='L245'></a><a href='#L245'>245</a>
|
|
311
|
+
<a name='L246'></a><a href='#L246'>246</a>
|
|
312
|
+
<a name='L247'></a><a href='#L247'>247</a>
|
|
313
|
+
<a name='L248'></a><a href='#L248'>248</a>
|
|
314
|
+
<a name='L249'></a><a href='#L249'>249</a>
|
|
315
|
+
<a name='L250'></a><a href='#L250'>250</a>
|
|
316
|
+
<a name='L251'></a><a href='#L251'>251</a>
|
|
317
|
+
<a name='L252'></a><a href='#L252'>252</a>
|
|
318
|
+
<a name='L253'></a><a href='#L253'>253</a>
|
|
319
|
+
<a name='L254'></a><a href='#L254'>254</a>
|
|
320
|
+
<a name='L255'></a><a href='#L255'>255</a>
|
|
321
|
+
<a name='L256'></a><a href='#L256'>256</a>
|
|
322
|
+
<a name='L257'></a><a href='#L257'>257</a>
|
|
323
|
+
<a name='L258'></a><a href='#L258'>258</a>
|
|
324
|
+
<a name='L259'></a><a href='#L259'>259</a>
|
|
325
|
+
<a name='L260'></a><a href='#L260'>260</a>
|
|
326
|
+
<a name='L261'></a><a href='#L261'>261</a>
|
|
327
|
+
<a name='L262'></a><a href='#L262'>262</a>
|
|
328
|
+
<a name='L263'></a><a href='#L263'>263</a>
|
|
329
|
+
<a name='L264'></a><a href='#L264'>264</a>
|
|
330
|
+
<a name='L265'></a><a href='#L265'>265</a>
|
|
331
|
+
<a name='L266'></a><a href='#L266'>266</a>
|
|
332
|
+
<a name='L267'></a><a href='#L267'>267</a>
|
|
333
|
+
<a name='L268'></a><a href='#L268'>268</a>
|
|
334
|
+
<a name='L269'></a><a href='#L269'>269</a>
|
|
335
|
+
<a name='L270'></a><a href='#L270'>270</a>
|
|
336
|
+
<a name='L271'></a><a href='#L271'>271</a>
|
|
337
|
+
<a name='L272'></a><a href='#L272'>272</a>
|
|
338
|
+
<a name='L273'></a><a href='#L273'>273</a>
|
|
339
|
+
<a name='L274'></a><a href='#L274'>274</a>
|
|
340
|
+
<a name='L275'></a><a href='#L275'>275</a>
|
|
341
|
+
<a name='L276'></a><a href='#L276'>276</a>
|
|
342
|
+
<a name='L277'></a><a href='#L277'>277</a>
|
|
343
|
+
<a name='L278'></a><a href='#L278'>278</a>
|
|
344
|
+
<a name='L279'></a><a href='#L279'>279</a>
|
|
345
|
+
<a name='L280'></a><a href='#L280'>280</a>
|
|
346
|
+
<a name='L281'></a><a href='#L281'>281</a>
|
|
347
|
+
<a name='L282'></a><a href='#L282'>282</a>
|
|
348
|
+
<a name='L283'></a><a href='#L283'>283</a>
|
|
349
|
+
<a name='L284'></a><a href='#L284'>284</a>
|
|
350
|
+
<a name='L285'></a><a href='#L285'>285</a>
|
|
351
|
+
<a name='L286'></a><a href='#L286'>286</a>
|
|
352
|
+
<a name='L287'></a><a href='#L287'>287</a>
|
|
353
|
+
<a name='L288'></a><a href='#L288'>288</a>
|
|
354
|
+
<a name='L289'></a><a href='#L289'>289</a>
|
|
355
|
+
<a name='L290'></a><a href='#L290'>290</a>
|
|
356
|
+
<a name='L291'></a><a href='#L291'>291</a>
|
|
357
|
+
<a name='L292'></a><a href='#L292'>292</a>
|
|
358
|
+
<a name='L293'></a><a href='#L293'>293</a>
|
|
359
|
+
<a name='L294'></a><a href='#L294'>294</a>
|
|
360
|
+
<a name='L295'></a><a href='#L295'>295</a>
|
|
361
|
+
<a name='L296'></a><a href='#L296'>296</a>
|
|
362
|
+
<a name='L297'></a><a href='#L297'>297</a>
|
|
363
|
+
<a name='L298'></a><a href='#L298'>298</a>
|
|
364
|
+
<a name='L299'></a><a href='#L299'>299</a>
|
|
365
|
+
<a name='L300'></a><a href='#L300'>300</a>
|
|
366
|
+
<a name='L301'></a><a href='#L301'>301</a>
|
|
367
|
+
<a name='L302'></a><a href='#L302'>302</a>
|
|
368
|
+
<a name='L303'></a><a href='#L303'>303</a>
|
|
369
|
+
<a name='L304'></a><a href='#L304'>304</a>
|
|
370
|
+
<a name='L305'></a><a href='#L305'>305</a>
|
|
371
|
+
<a name='L306'></a><a href='#L306'>306</a>
|
|
372
|
+
<a name='L307'></a><a href='#L307'>307</a>
|
|
373
|
+
<a name='L308'></a><a href='#L308'>308</a>
|
|
374
|
+
<a name='L309'></a><a href='#L309'>309</a>
|
|
375
|
+
<a name='L310'></a><a href='#L310'>310</a>
|
|
376
|
+
<a name='L311'></a><a href='#L311'>311</a>
|
|
377
|
+
<a name='L312'></a><a href='#L312'>312</a>
|
|
378
|
+
<a name='L313'></a><a href='#L313'>313</a>
|
|
379
|
+
<a name='L314'></a><a href='#L314'>314</a>
|
|
380
|
+
<a name='L315'></a><a href='#L315'>315</a>
|
|
381
|
+
<a name='L316'></a><a href='#L316'>316</a>
|
|
382
|
+
<a name='L317'></a><a href='#L317'>317</a>
|
|
383
|
+
<a name='L318'></a><a href='#L318'>318</a>
|
|
384
|
+
<a name='L319'></a><a href='#L319'>319</a>
|
|
385
|
+
<a name='L320'></a><a href='#L320'>320</a>
|
|
386
|
+
<a name='L321'></a><a href='#L321'>321</a>
|
|
387
|
+
<a name='L322'></a><a href='#L322'>322</a>
|
|
388
|
+
<a name='L323'></a><a href='#L323'>323</a>
|
|
389
|
+
<a name='L324'></a><a href='#L324'>324</a>
|
|
390
|
+
<a name='L325'></a><a href='#L325'>325</a>
|
|
391
|
+
<a name='L326'></a><a href='#L326'>326</a>
|
|
392
|
+
<a name='L327'></a><a href='#L327'>327</a>
|
|
393
|
+
<a name='L328'></a><a href='#L328'>328</a>
|
|
394
|
+
<a name='L329'></a><a href='#L329'>329</a>
|
|
395
|
+
<a name='L330'></a><a href='#L330'>330</a>
|
|
396
|
+
<a name='L331'></a><a href='#L331'>331</a>
|
|
397
|
+
<a name='L332'></a><a href='#L332'>332</a>
|
|
398
|
+
<a name='L333'></a><a href='#L333'>333</a>
|
|
399
|
+
<a name='L334'></a><a href='#L334'>334</a>
|
|
400
|
+
<a name='L335'></a><a href='#L335'>335</a>
|
|
401
|
+
<a name='L336'></a><a href='#L336'>336</a>
|
|
402
|
+
<a name='L337'></a><a href='#L337'>337</a>
|
|
403
|
+
<a name='L338'></a><a href='#L338'>338</a>
|
|
404
|
+
<a name='L339'></a><a href='#L339'>339</a>
|
|
405
|
+
<a name='L340'></a><a href='#L340'>340</a>
|
|
406
|
+
<a name='L341'></a><a href='#L341'>341</a>
|
|
407
|
+
<a name='L342'></a><a href='#L342'>342</a>
|
|
408
|
+
<a name='L343'></a><a href='#L343'>343</a>
|
|
409
|
+
<a name='L344'></a><a href='#L344'>344</a>
|
|
410
|
+
<a name='L345'></a><a href='#L345'>345</a>
|
|
411
|
+
<a name='L346'></a><a href='#L346'>346</a>
|
|
412
|
+
<a name='L347'></a><a href='#L347'>347</a>
|
|
413
|
+
<a name='L348'></a><a href='#L348'>348</a>
|
|
414
|
+
<a name='L349'></a><a href='#L349'>349</a>
|
|
415
|
+
<a name='L350'></a><a href='#L350'>350</a>
|
|
416
|
+
<a name='L351'></a><a href='#L351'>351</a>
|
|
417
|
+
<a name='L352'></a><a href='#L352'>352</a>
|
|
418
|
+
<a name='L353'></a><a href='#L353'>353</a>
|
|
419
|
+
<a name='L354'></a><a href='#L354'>354</a>
|
|
420
|
+
<a name='L355'></a><a href='#L355'>355</a>
|
|
421
|
+
<a name='L356'></a><a href='#L356'>356</a>
|
|
422
|
+
<a name='L357'></a><a href='#L357'>357</a>
|
|
423
|
+
<a name='L358'></a><a href='#L358'>358</a>
|
|
424
|
+
<a name='L359'></a><a href='#L359'>359</a>
|
|
425
|
+
<a name='L360'></a><a href='#L360'>360</a>
|
|
426
|
+
<a name='L361'></a><a href='#L361'>361</a>
|
|
427
|
+
<a name='L362'></a><a href='#L362'>362</a>
|
|
428
|
+
<a name='L363'></a><a href='#L363'>363</a>
|
|
429
|
+
<a name='L364'></a><a href='#L364'>364</a>
|
|
430
|
+
<a name='L365'></a><a href='#L365'>365</a>
|
|
431
|
+
<a name='L366'></a><a href='#L366'>366</a>
|
|
432
|
+
<a name='L367'></a><a href='#L367'>367</a>
|
|
433
|
+
<a name='L368'></a><a href='#L368'>368</a>
|
|
434
|
+
<a name='L369'></a><a href='#L369'>369</a>
|
|
435
|
+
<a name='L370'></a><a href='#L370'>370</a>
|
|
436
|
+
<a name='L371'></a><a href='#L371'>371</a>
|
|
437
|
+
<a name='L372'></a><a href='#L372'>372</a>
|
|
438
|
+
<a name='L373'></a><a href='#L373'>373</a>
|
|
439
|
+
<a name='L374'></a><a href='#L374'>374</a>
|
|
440
|
+
<a name='L375'></a><a href='#L375'>375</a>
|
|
441
|
+
<a name='L376'></a><a href='#L376'>376</a>
|
|
442
|
+
<a name='L377'></a><a href='#L377'>377</a>
|
|
443
|
+
<a name='L378'></a><a href='#L378'>378</a>
|
|
444
|
+
<a name='L379'></a><a href='#L379'>379</a>
|
|
445
|
+
<a name='L380'></a><a href='#L380'>380</a>
|
|
446
|
+
<a name='L381'></a><a href='#L381'>381</a>
|
|
447
|
+
<a name='L382'></a><a href='#L382'>382</a>
|
|
448
|
+
<a name='L383'></a><a href='#L383'>383</a>
|
|
449
|
+
<a name='L384'></a><a href='#L384'>384</a>
|
|
450
|
+
<a name='L385'></a><a href='#L385'>385</a>
|
|
451
|
+
<a name='L386'></a><a href='#L386'>386</a>
|
|
452
|
+
<a name='L387'></a><a href='#L387'>387</a>
|
|
453
|
+
<a name='L388'></a><a href='#L388'>388</a>
|
|
454
|
+
<a name='L389'></a><a href='#L389'>389</a>
|
|
455
|
+
<a name='L390'></a><a href='#L390'>390</a>
|
|
456
|
+
<a name='L391'></a><a href='#L391'>391</a>
|
|
457
|
+
<a name='L392'></a><a href='#L392'>392</a>
|
|
458
|
+
<a name='L393'></a><a href='#L393'>393</a>
|
|
459
|
+
<a name='L394'></a><a href='#L394'>394</a>
|
|
460
|
+
<a name='L395'></a><a href='#L395'>395</a>
|
|
461
|
+
<a name='L396'></a><a href='#L396'>396</a>
|
|
462
|
+
<a name='L397'></a><a href='#L397'>397</a>
|
|
463
|
+
<a name='L398'></a><a href='#L398'>398</a>
|
|
464
|
+
<a name='L399'></a><a href='#L399'>399</a>
|
|
465
|
+
<a name='L400'></a><a href='#L400'>400</a>
|
|
466
|
+
<a name='L401'></a><a href='#L401'>401</a>
|
|
467
|
+
<a name='L402'></a><a href='#L402'>402</a>
|
|
468
|
+
<a name='L403'></a><a href='#L403'>403</a>
|
|
469
|
+
<a name='L404'></a><a href='#L404'>404</a>
|
|
470
|
+
<a name='L405'></a><a href='#L405'>405</a>
|
|
471
|
+
<a name='L406'></a><a href='#L406'>406</a>
|
|
472
|
+
<a name='L407'></a><a href='#L407'>407</a>
|
|
473
|
+
<a name='L408'></a><a href='#L408'>408</a>
|
|
474
|
+
<a name='L409'></a><a href='#L409'>409</a>
|
|
475
|
+
<a name='L410'></a><a href='#L410'>410</a>
|
|
476
|
+
<a name='L411'></a><a href='#L411'>411</a>
|
|
477
|
+
<a name='L412'></a><a href='#L412'>412</a>
|
|
478
|
+
<a name='L413'></a><a href='#L413'>413</a>
|
|
479
|
+
<a name='L414'></a><a href='#L414'>414</a>
|
|
480
|
+
<a name='L415'></a><a href='#L415'>415</a>
|
|
481
|
+
<a name='L416'></a><a href='#L416'>416</a>
|
|
482
|
+
<a name='L417'></a><a href='#L417'>417</a>
|
|
483
|
+
<a name='L418'></a><a href='#L418'>418</a>
|
|
484
|
+
<a name='L419'></a><a href='#L419'>419</a>
|
|
485
|
+
<a name='L420'></a><a href='#L420'>420</a>
|
|
486
|
+
<a name='L421'></a><a href='#L421'>421</a>
|
|
487
|
+
<a name='L422'></a><a href='#L422'>422</a>
|
|
488
|
+
<a name='L423'></a><a href='#L423'>423</a>
|
|
489
|
+
<a name='L424'></a><a href='#L424'>424</a>
|
|
490
|
+
<a name='L425'></a><a href='#L425'>425</a>
|
|
491
|
+
<a name='L426'></a><a href='#L426'>426</a>
|
|
492
|
+
<a name='L427'></a><a href='#L427'>427</a>
|
|
493
|
+
<a name='L428'></a><a href='#L428'>428</a>
|
|
494
|
+
<a name='L429'></a><a href='#L429'>429</a>
|
|
495
|
+
<a name='L430'></a><a href='#L430'>430</a>
|
|
496
|
+
<a name='L431'></a><a href='#L431'>431</a>
|
|
497
|
+
<a name='L432'></a><a href='#L432'>432</a>
|
|
498
|
+
<a name='L433'></a><a href='#L433'>433</a>
|
|
499
|
+
<a name='L434'></a><a href='#L434'>434</a>
|
|
500
|
+
<a name='L435'></a><a href='#L435'>435</a>
|
|
501
|
+
<a name='L436'></a><a href='#L436'>436</a>
|
|
502
|
+
<a name='L437'></a><a href='#L437'>437</a>
|
|
503
|
+
<a name='L438'></a><a href='#L438'>438</a>
|
|
504
|
+
<a name='L439'></a><a href='#L439'>439</a>
|
|
505
|
+
<a name='L440'></a><a href='#L440'>440</a>
|
|
506
|
+
<a name='L441'></a><a href='#L441'>441</a>
|
|
507
|
+
<a name='L442'></a><a href='#L442'>442</a>
|
|
508
|
+
<a name='L443'></a><a href='#L443'>443</a>
|
|
509
|
+
<a name='L444'></a><a href='#L444'>444</a>
|
|
510
|
+
<a name='L445'></a><a href='#L445'>445</a>
|
|
511
|
+
<a name='L446'></a><a href='#L446'>446</a>
|
|
512
|
+
<a name='L447'></a><a href='#L447'>447</a>
|
|
513
|
+
<a name='L448'></a><a href='#L448'>448</a>
|
|
514
|
+
<a name='L449'></a><a href='#L449'>449</a>
|
|
515
|
+
<a name='L450'></a><a href='#L450'>450</a>
|
|
516
|
+
<a name='L451'></a><a href='#L451'>451</a>
|
|
517
|
+
<a name='L452'></a><a href='#L452'>452</a>
|
|
518
|
+
<a name='L453'></a><a href='#L453'>453</a>
|
|
519
|
+
<a name='L454'></a><a href='#L454'>454</a>
|
|
520
|
+
<a name='L455'></a><a href='#L455'>455</a>
|
|
521
|
+
<a name='L456'></a><a href='#L456'>456</a>
|
|
522
|
+
<a name='L457'></a><a href='#L457'>457</a>
|
|
523
|
+
<a name='L458'></a><a href='#L458'>458</a>
|
|
524
|
+
<a name='L459'></a><a href='#L459'>459</a>
|
|
525
|
+
<a name='L460'></a><a href='#L460'>460</a>
|
|
526
|
+
<a name='L461'></a><a href='#L461'>461</a>
|
|
527
|
+
<a name='L462'></a><a href='#L462'>462</a>
|
|
528
|
+
<a name='L463'></a><a href='#L463'>463</a>
|
|
529
|
+
<a name='L464'></a><a href='#L464'>464</a>
|
|
530
|
+
<a name='L465'></a><a href='#L465'>465</a>
|
|
531
|
+
<a name='L466'></a><a href='#L466'>466</a>
|
|
532
|
+
<a name='L467'></a><a href='#L467'>467</a>
|
|
533
|
+
<a name='L468'></a><a href='#L468'>468</a>
|
|
534
|
+
<a name='L469'></a><a href='#L469'>469</a>
|
|
535
|
+
<a name='L470'></a><a href='#L470'>470</a>
|
|
536
|
+
<a name='L471'></a><a href='#L471'>471</a>
|
|
537
|
+
<a name='L472'></a><a href='#L472'>472</a>
|
|
538
|
+
<a name='L473'></a><a href='#L473'>473</a>
|
|
539
|
+
<a name='L474'></a><a href='#L474'>474</a>
|
|
540
|
+
<a name='L475'></a><a href='#L475'>475</a>
|
|
541
|
+
<a name='L476'></a><a href='#L476'>476</a>
|
|
542
|
+
<a name='L477'></a><a href='#L477'>477</a>
|
|
543
|
+
<a name='L478'></a><a href='#L478'>478</a>
|
|
544
|
+
<a name='L479'></a><a href='#L479'>479</a>
|
|
545
|
+
<a name='L480'></a><a href='#L480'>480</a>
|
|
546
|
+
<a name='L481'></a><a href='#L481'>481</a>
|
|
547
|
+
<a name='L482'></a><a href='#L482'>482</a>
|
|
548
|
+
<a name='L483'></a><a href='#L483'>483</a>
|
|
549
|
+
<a name='L484'></a><a href='#L484'>484</a>
|
|
550
|
+
<a name='L485'></a><a href='#L485'>485</a>
|
|
551
|
+
<a name='L486'></a><a href='#L486'>486</a>
|
|
552
|
+
<a name='L487'></a><a href='#L487'>487</a>
|
|
553
|
+
<a name='L488'></a><a href='#L488'>488</a>
|
|
554
|
+
<a name='L489'></a><a href='#L489'>489</a>
|
|
555
|
+
<a name='L490'></a><a href='#L490'>490</a>
|
|
556
|
+
<a name='L491'></a><a href='#L491'>491</a>
|
|
557
|
+
<a name='L492'></a><a href='#L492'>492</a>
|
|
558
|
+
<a name='L493'></a><a href='#L493'>493</a>
|
|
559
|
+
<a name='L494'></a><a href='#L494'>494</a>
|
|
560
|
+
<a name='L495'></a><a href='#L495'>495</a>
|
|
561
|
+
<a name='L496'></a><a href='#L496'>496</a>
|
|
562
|
+
<a name='L497'></a><a href='#L497'>497</a>
|
|
563
|
+
<a name='L498'></a><a href='#L498'>498</a>
|
|
564
|
+
<a name='L499'></a><a href='#L499'>499</a>
|
|
565
|
+
<a name='L500'></a><a href='#L500'>500</a>
|
|
566
|
+
<a name='L501'></a><a href='#L501'>501</a>
|
|
567
|
+
<a name='L502'></a><a href='#L502'>502</a>
|
|
568
|
+
<a name='L503'></a><a href='#L503'>503</a>
|
|
569
|
+
<a name='L504'></a><a href='#L504'>504</a>
|
|
570
|
+
<a name='L505'></a><a href='#L505'>505</a>
|
|
571
|
+
<a name='L506'></a><a href='#L506'>506</a>
|
|
572
|
+
<a name='L507'></a><a href='#L507'>507</a>
|
|
573
|
+
<a name='L508'></a><a href='#L508'>508</a>
|
|
574
|
+
<a name='L509'></a><a href='#L509'>509</a>
|
|
575
|
+
<a name='L510'></a><a href='#L510'>510</a>
|
|
576
|
+
<a name='L511'></a><a href='#L511'>511</a>
|
|
577
|
+
<a name='L512'></a><a href='#L512'>512</a>
|
|
578
|
+
<a name='L513'></a><a href='#L513'>513</a>
|
|
579
|
+
<a name='L514'></a><a href='#L514'>514</a>
|
|
580
|
+
<a name='L515'></a><a href='#L515'>515</a>
|
|
581
|
+
<a name='L516'></a><a href='#L516'>516</a>
|
|
582
|
+
<a name='L517'></a><a href='#L517'>517</a>
|
|
583
|
+
<a name='L518'></a><a href='#L518'>518</a>
|
|
584
|
+
<a name='L519'></a><a href='#L519'>519</a>
|
|
585
|
+
<a name='L520'></a><a href='#L520'>520</a>
|
|
586
|
+
<a name='L521'></a><a href='#L521'>521</a>
|
|
587
|
+
<a name='L522'></a><a href='#L522'>522</a>
|
|
588
|
+
<a name='L523'></a><a href='#L523'>523</a>
|
|
589
|
+
<a name='L524'></a><a href='#L524'>524</a>
|
|
590
|
+
<a name='L525'></a><a href='#L525'>525</a>
|
|
591
|
+
<a name='L526'></a><a href='#L526'>526</a>
|
|
592
|
+
<a name='L527'></a><a href='#L527'>527</a>
|
|
593
|
+
<a name='L528'></a><a href='#L528'>528</a>
|
|
594
|
+
<a name='L529'></a><a href='#L529'>529</a>
|
|
595
|
+
<a name='L530'></a><a href='#L530'>530</a>
|
|
596
|
+
<a name='L531'></a><a href='#L531'>531</a>
|
|
597
|
+
<a name='L532'></a><a href='#L532'>532</a>
|
|
598
|
+
<a name='L533'></a><a href='#L533'>533</a>
|
|
599
|
+
<a name='L534'></a><a href='#L534'>534</a>
|
|
600
|
+
<a name='L535'></a><a href='#L535'>535</a>
|
|
601
|
+
<a name='L536'></a><a href='#L536'>536</a>
|
|
602
|
+
<a name='L537'></a><a href='#L537'>537</a>
|
|
603
|
+
<a name='L538'></a><a href='#L538'>538</a>
|
|
604
|
+
<a name='L539'></a><a href='#L539'>539</a>
|
|
605
|
+
<a name='L540'></a><a href='#L540'>540</a>
|
|
606
|
+
<a name='L541'></a><a href='#L541'>541</a>
|
|
607
|
+
<a name='L542'></a><a href='#L542'>542</a>
|
|
608
|
+
<a name='L543'></a><a href='#L543'>543</a>
|
|
609
|
+
<a name='L544'></a><a href='#L544'>544</a>
|
|
610
|
+
<a name='L545'></a><a href='#L545'>545</a>
|
|
611
|
+
<a name='L546'></a><a href='#L546'>546</a>
|
|
612
|
+
<a name='L547'></a><a href='#L547'>547</a>
|
|
613
|
+
<a name='L548'></a><a href='#L548'>548</a>
|
|
614
|
+
<a name='L549'></a><a href='#L549'>549</a>
|
|
615
|
+
<a name='L550'></a><a href='#L550'>550</a>
|
|
616
|
+
<a name='L551'></a><a href='#L551'>551</a>
|
|
617
|
+
<a name='L552'></a><a href='#L552'>552</a>
|
|
618
|
+
<a name='L553'></a><a href='#L553'>553</a>
|
|
619
|
+
<a name='L554'></a><a href='#L554'>554</a>
|
|
620
|
+
<a name='L555'></a><a href='#L555'>555</a>
|
|
621
|
+
<a name='L556'></a><a href='#L556'>556</a>
|
|
622
|
+
<a name='L557'></a><a href='#L557'>557</a>
|
|
623
|
+
<a name='L558'></a><a href='#L558'>558</a>
|
|
624
|
+
<a name='L559'></a><a href='#L559'>559</a>
|
|
625
|
+
<a name='L560'></a><a href='#L560'>560</a>
|
|
626
|
+
<a name='L561'></a><a href='#L561'>561</a>
|
|
627
|
+
<a name='L562'></a><a href='#L562'>562</a>
|
|
628
|
+
<a name='L563'></a><a href='#L563'>563</a>
|
|
629
|
+
<a name='L564'></a><a href='#L564'>564</a>
|
|
630
|
+
<a name='L565'></a><a href='#L565'>565</a>
|
|
631
|
+
<a name='L566'></a><a href='#L566'>566</a>
|
|
632
|
+
<a name='L567'></a><a href='#L567'>567</a>
|
|
633
|
+
<a name='L568'></a><a href='#L568'>568</a>
|
|
634
|
+
<a name='L569'></a><a href='#L569'>569</a>
|
|
635
|
+
<a name='L570'></a><a href='#L570'>570</a>
|
|
636
|
+
<a name='L571'></a><a href='#L571'>571</a>
|
|
637
|
+
<a name='L572'></a><a href='#L572'>572</a>
|
|
638
|
+
<a name='L573'></a><a href='#L573'>573</a>
|
|
639
|
+
<a name='L574'></a><a href='#L574'>574</a>
|
|
640
|
+
<a name='L575'></a><a href='#L575'>575</a>
|
|
641
|
+
<a name='L576'></a><a href='#L576'>576</a>
|
|
642
|
+
<a name='L577'></a><a href='#L577'>577</a>
|
|
643
|
+
<a name='L578'></a><a href='#L578'>578</a>
|
|
644
|
+
<a name='L579'></a><a href='#L579'>579</a>
|
|
645
|
+
<a name='L580'></a><a href='#L580'>580</a>
|
|
646
|
+
<a name='L581'></a><a href='#L581'>581</a>
|
|
647
|
+
<a name='L582'></a><a href='#L582'>582</a>
|
|
648
|
+
<a name='L583'></a><a href='#L583'>583</a>
|
|
649
|
+
<a name='L584'></a><a href='#L584'>584</a>
|
|
650
|
+
<a name='L585'></a><a href='#L585'>585</a>
|
|
651
|
+
<a name='L586'></a><a href='#L586'>586</a>
|
|
652
|
+
<a name='L587'></a><a href='#L587'>587</a>
|
|
653
|
+
<a name='L588'></a><a href='#L588'>588</a>
|
|
654
|
+
<a name='L589'></a><a href='#L589'>589</a>
|
|
655
|
+
<a name='L590'></a><a href='#L590'>590</a>
|
|
656
|
+
<a name='L591'></a><a href='#L591'>591</a>
|
|
657
|
+
<a name='L592'></a><a href='#L592'>592</a>
|
|
658
|
+
<a name='L593'></a><a href='#L593'>593</a>
|
|
659
|
+
<a name='L594'></a><a href='#L594'>594</a>
|
|
660
|
+
<a name='L595'></a><a href='#L595'>595</a>
|
|
661
|
+
<a name='L596'></a><a href='#L596'>596</a></td><td class="line-coverage quiet"><span class="cline-any cline-yes">1x</span>
|
|
662
|
+
<span class="cline-any cline-yes">1x</span>
|
|
663
|
+
<span class="cline-any cline-yes">1x</span>
|
|
664
|
+
<span class="cline-any cline-yes">1x</span>
|
|
665
|
+
<span class="cline-any cline-yes">1x</span>
|
|
666
|
+
<span class="cline-any cline-yes">1x</span>
|
|
667
|
+
<span class="cline-any cline-yes">1x</span>
|
|
668
|
+
<span class="cline-any cline-yes">1x</span>
|
|
669
|
+
<span class="cline-any cline-yes">1x</span>
|
|
670
|
+
<span class="cline-any cline-yes">1x</span>
|
|
671
|
+
<span class="cline-any cline-yes">1x</span>
|
|
672
|
+
<span class="cline-any cline-yes">1x</span>
|
|
673
|
+
<span class="cline-any cline-yes">1x</span>
|
|
674
|
+
<span class="cline-any cline-yes">1x</span>
|
|
675
|
+
<span class="cline-any cline-yes">1x</span>
|
|
676
|
+
<span class="cline-any cline-yes">1x</span>
|
|
677
|
+
<span class="cline-any cline-yes">1x</span>
|
|
678
|
+
<span class="cline-any cline-yes">1x</span>
|
|
679
|
+
<span class="cline-any cline-yes">1x</span>
|
|
680
|
+
<span class="cline-any cline-yes">1x</span>
|
|
681
|
+
<span class="cline-any cline-yes">1x</span>
|
|
682
|
+
<span class="cline-any cline-yes">1x</span>
|
|
683
|
+
<span class="cline-any cline-yes">1x</span>
|
|
684
|
+
<span class="cline-any cline-yes">1x</span>
|
|
685
|
+
<span class="cline-any cline-yes">1x</span>
|
|
686
|
+
<span class="cline-any cline-yes">1x</span>
|
|
687
|
+
<span class="cline-any cline-yes">1x</span>
|
|
688
|
+
<span class="cline-any cline-yes">1x</span>
|
|
689
|
+
<span class="cline-any cline-yes">1x</span>
|
|
690
|
+
<span class="cline-any cline-yes">1x</span>
|
|
691
|
+
<span class="cline-any cline-yes">1x</span>
|
|
692
|
+
<span class="cline-any cline-yes">1x</span>
|
|
693
|
+
<span class="cline-any cline-yes">1x</span>
|
|
694
|
+
<span class="cline-any cline-yes">1x</span>
|
|
695
|
+
<span class="cline-any cline-yes">1x</span>
|
|
696
|
+
<span class="cline-any cline-yes">1x</span>
|
|
697
|
+
<span class="cline-any cline-yes">1x</span>
|
|
698
|
+
<span class="cline-any cline-yes">1x</span>
|
|
699
|
+
<span class="cline-any cline-yes">1x</span>
|
|
700
|
+
<span class="cline-any cline-yes">1x</span>
|
|
701
|
+
<span class="cline-any cline-yes">1x</span>
|
|
702
|
+
<span class="cline-any cline-yes">1x</span>
|
|
703
|
+
<span class="cline-any cline-yes">1x</span>
|
|
704
|
+
<span class="cline-any cline-yes">1x</span>
|
|
705
|
+
<span class="cline-any cline-yes">1x</span>
|
|
706
|
+
<span class="cline-any cline-yes">1x</span>
|
|
707
|
+
<span class="cline-any cline-yes">1x</span>
|
|
708
|
+
<span class="cline-any cline-yes">1x</span>
|
|
709
|
+
<span class="cline-any cline-yes">1x</span>
|
|
710
|
+
<span class="cline-any cline-yes">1x</span>
|
|
711
|
+
<span class="cline-any cline-yes">1x</span>
|
|
712
|
+
<span class="cline-any cline-yes">1x</span>
|
|
713
|
+
<span class="cline-any cline-yes">1x</span>
|
|
714
|
+
<span class="cline-any cline-yes">1x</span>
|
|
715
|
+
<span class="cline-any cline-yes">1x</span>
|
|
716
|
+
<span class="cline-any cline-yes">1x</span>
|
|
717
|
+
<span class="cline-any cline-yes">1x</span>
|
|
718
|
+
<span class="cline-any cline-yes">108x</span>
|
|
719
|
+
<span class="cline-any cline-yes">108x</span>
|
|
720
|
+
<span class="cline-any cline-yes">108x</span>
|
|
721
|
+
<span class="cline-any cline-yes">108x</span>
|
|
722
|
+
<span class="cline-any cline-yes">108x</span>
|
|
723
|
+
<span class="cline-any cline-yes">108x</span>
|
|
724
|
+
<span class="cline-any cline-yes">108x</span>
|
|
725
|
+
<span class="cline-any cline-yes">108x</span>
|
|
726
|
+
<span class="cline-any cline-yes">108x</span>
|
|
727
|
+
<span class="cline-any cline-yes">108x</span>
|
|
728
|
+
<span class="cline-any cline-yes">108x</span>
|
|
729
|
+
<span class="cline-any cline-yes">108x</span>
|
|
730
|
+
<span class="cline-any cline-yes">108x</span>
|
|
731
|
+
<span class="cline-any cline-yes">108x</span>
|
|
732
|
+
<span class="cline-any cline-yes">108x</span>
|
|
733
|
+
<span class="cline-any cline-yes">108x</span>
|
|
734
|
+
<span class="cline-any cline-yes">108x</span>
|
|
735
|
+
<span class="cline-any cline-yes">108x</span>
|
|
736
|
+
<span class="cline-any cline-yes">108x</span>
|
|
737
|
+
<span class="cline-any cline-yes">108x</span>
|
|
738
|
+
<span class="cline-any cline-yes">108x</span>
|
|
739
|
+
<span class="cline-any cline-yes">108x</span>
|
|
740
|
+
<span class="cline-any cline-yes">108x</span>
|
|
741
|
+
<span class="cline-any cline-yes">5x</span>
|
|
742
|
+
<span class="cline-any cline-yes">108x</span>
|
|
743
|
+
<span class="cline-any cline-yes">108x</span>
|
|
744
|
+
<span class="cline-any cline-yes">108x</span>
|
|
745
|
+
<span class="cline-any cline-yes">108x</span>
|
|
746
|
+
<span class="cline-any cline-yes">108x</span>
|
|
747
|
+
<span class="cline-any cline-yes">108x</span>
|
|
748
|
+
<span class="cline-any cline-no"> </span>
|
|
749
|
+
<span class="cline-any cline-no"> </span>
|
|
750
|
+
<span class="cline-any cline-yes">108x</span>
|
|
751
|
+
<span class="cline-any cline-yes">108x</span>
|
|
752
|
+
<span class="cline-any cline-yes">108x</span>
|
|
753
|
+
<span class="cline-any cline-yes">108x</span>
|
|
754
|
+
<span class="cline-any cline-yes">108x</span>
|
|
755
|
+
<span class="cline-any cline-yes">108x</span>
|
|
756
|
+
<span class="cline-any cline-yes">5x</span>
|
|
757
|
+
<span class="cline-any cline-yes">5x</span>
|
|
758
|
+
<span class="cline-any cline-yes">5x</span>
|
|
759
|
+
<span class="cline-any cline-yes">5x</span>
|
|
760
|
+
<span class="cline-any cline-yes">108x</span>
|
|
761
|
+
<span class="cline-any cline-yes">108x</span>
|
|
762
|
+
<span class="cline-any cline-yes">108x</span>
|
|
763
|
+
<span class="cline-any cline-yes">108x</span>
|
|
764
|
+
<span class="cline-any cline-yes">108x</span>
|
|
765
|
+
<span class="cline-any cline-yes">108x</span>
|
|
766
|
+
<span class="cline-any cline-yes">108x</span>
|
|
767
|
+
<span class="cline-any cline-yes">37x</span>
|
|
768
|
+
<span class="cline-any cline-yes">37x</span>
|
|
769
|
+
<span class="cline-any cline-yes">108x</span>
|
|
770
|
+
<span class="cline-any cline-yes">108x</span>
|
|
771
|
+
<span class="cline-any cline-yes">108x</span>
|
|
772
|
+
<span class="cline-any cline-yes">108x</span>
|
|
773
|
+
<span class="cline-any cline-yes">108x</span>
|
|
774
|
+
<span class="cline-any cline-yes">108x</span>
|
|
775
|
+
<span class="cline-any cline-yes">108x</span>
|
|
776
|
+
<span class="cline-any cline-yes">108x</span>
|
|
777
|
+
<span class="cline-any cline-yes">108x</span>
|
|
778
|
+
<span class="cline-any cline-yes">108x</span>
|
|
779
|
+
<span class="cline-any cline-yes">108x</span>
|
|
780
|
+
<span class="cline-any cline-yes">108x</span>
|
|
781
|
+
<span class="cline-any cline-yes">108x</span>
|
|
782
|
+
<span class="cline-any cline-yes">5x</span>
|
|
783
|
+
<span class="cline-any cline-yes">5x</span>
|
|
784
|
+
<span class="cline-any cline-yes">5x</span>
|
|
785
|
+
<span class="cline-any cline-yes">5x</span>
|
|
786
|
+
<span class="cline-any cline-yes">5x</span>
|
|
787
|
+
<span class="cline-any cline-yes">5x</span>
|
|
788
|
+
<span class="cline-any cline-yes">5x</span>
|
|
789
|
+
<span class="cline-any cline-yes">5x</span>
|
|
790
|
+
<span class="cline-any cline-yes">5x</span>
|
|
791
|
+
<span class="cline-any cline-yes">5x</span>
|
|
792
|
+
<span class="cline-any cline-yes">5x</span>
|
|
793
|
+
<span class="cline-any cline-yes">5x</span>
|
|
794
|
+
<span class="cline-any cline-yes">5x</span>
|
|
795
|
+
<span class="cline-any cline-yes">5x</span>
|
|
796
|
+
<span class="cline-any cline-yes">5x</span>
|
|
797
|
+
<span class="cline-any cline-yes">5x</span>
|
|
798
|
+
<span class="cline-any cline-yes">5x</span>
|
|
799
|
+
<span class="cline-any cline-yes">5x</span>
|
|
800
|
+
<span class="cline-any cline-yes">5x</span>
|
|
801
|
+
<span class="cline-any cline-yes">5x</span>
|
|
802
|
+
<span class="cline-any cline-yes">5x</span>
|
|
803
|
+
<span class="cline-any cline-yes">5x</span>
|
|
804
|
+
<span class="cline-any cline-yes">5x</span>
|
|
805
|
+
<span class="cline-any cline-yes">5x</span>
|
|
806
|
+
<span class="cline-any cline-yes">5x</span>
|
|
807
|
+
<span class="cline-any cline-yes">5x</span>
|
|
808
|
+
<span class="cline-any cline-yes">5x</span>
|
|
809
|
+
<span class="cline-any cline-yes">5x</span>
|
|
810
|
+
<span class="cline-any cline-yes">5x</span>
|
|
811
|
+
<span class="cline-any cline-yes">5x</span>
|
|
812
|
+
<span class="cline-any cline-yes">5x</span>
|
|
813
|
+
<span class="cline-any cline-yes">5x</span>
|
|
814
|
+
<span class="cline-any cline-yes">5x</span>
|
|
815
|
+
<span class="cline-any cline-yes">5x</span>
|
|
816
|
+
<span class="cline-any cline-yes">5x</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-no"> </span>
|
|
821
|
+
<span class="cline-any cline-no"> </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-yes">5x</span>
|
|
834
|
+
<span class="cline-any cline-yes">108x</span>
|
|
835
|
+
<span class="cline-any cline-yes">108x</span>
|
|
836
|
+
<span class="cline-any cline-yes">108x</span>
|
|
837
|
+
<span class="cline-any cline-yes">108x</span>
|
|
838
|
+
<span class="cline-any cline-yes">108x</span>
|
|
839
|
+
<span class="cline-any cline-yes">108x</span>
|
|
840
|
+
<span class="cline-any cline-yes">108x</span>
|
|
841
|
+
<span class="cline-any cline-yes">108x</span>
|
|
842
|
+
<span class="cline-any cline-yes">5x</span>
|
|
843
|
+
<span class="cline-any cline-yes">5x</span>
|
|
844
|
+
<span class="cline-any cline-yes">5x</span>
|
|
845
|
+
<span class="cline-any cline-yes">5x</span>
|
|
846
|
+
<span class="cline-any cline-yes">5x</span>
|
|
847
|
+
<span class="cline-any cline-yes">5x</span>
|
|
848
|
+
<span class="cline-any cline-yes">5x</span>
|
|
849
|
+
<span class="cline-any cline-yes">5x</span>
|
|
850
|
+
<span class="cline-any cline-yes">5x</span>
|
|
851
|
+
<span class="cline-any cline-yes">5x</span>
|
|
852
|
+
<span class="cline-any cline-yes">5x</span>
|
|
853
|
+
<span class="cline-any cline-yes">5x</span>
|
|
854
|
+
<span class="cline-any cline-yes">5x</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-yes">5x</span>
|
|
859
|
+
<span class="cline-any cline-yes">5x</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-yes">5x</span>
|
|
864
|
+
<span class="cline-any cline-yes">5x</span>
|
|
865
|
+
<span class="cline-any cline-yes">5x</span>
|
|
866
|
+
<span class="cline-any cline-yes">5x</span>
|
|
867
|
+
<span class="cline-any cline-yes">5x</span>
|
|
868
|
+
<span class="cline-any cline-yes">5x</span>
|
|
869
|
+
<span class="cline-any cline-yes">5x</span>
|
|
870
|
+
<span class="cline-any cline-yes">5x</span>
|
|
871
|
+
<span class="cline-any cline-yes">5x</span>
|
|
872
|
+
<span class="cline-any cline-yes">5x</span>
|
|
873
|
+
<span class="cline-any cline-yes">5x</span>
|
|
874
|
+
<span class="cline-any cline-yes">5x</span>
|
|
875
|
+
<span class="cline-any cline-yes">5x</span>
|
|
876
|
+
<span class="cline-any cline-yes">5x</span>
|
|
877
|
+
<span class="cline-any cline-yes">5x</span>
|
|
878
|
+
<span class="cline-any cline-yes">5x</span>
|
|
879
|
+
<span class="cline-any cline-yes">5x</span>
|
|
880
|
+
<span class="cline-any cline-yes">5x</span>
|
|
881
|
+
<span class="cline-any cline-yes">5x</span>
|
|
882
|
+
<span class="cline-any cline-yes">5x</span>
|
|
883
|
+
<span class="cline-any cline-yes">5x</span>
|
|
884
|
+
<span class="cline-any cline-yes">5x</span>
|
|
885
|
+
<span class="cline-any cline-yes">5x</span>
|
|
886
|
+
<span class="cline-any cline-yes">5x</span>
|
|
887
|
+
<span class="cline-any cline-yes">5x</span>
|
|
888
|
+
<span class="cline-any cline-yes">5x</span>
|
|
889
|
+
<span class="cline-any cline-yes">5x</span>
|
|
890
|
+
<span class="cline-any cline-yes">5x</span>
|
|
891
|
+
<span class="cline-any cline-yes">5x</span>
|
|
892
|
+
<span class="cline-any cline-yes">5x</span>
|
|
893
|
+
<span class="cline-any cline-yes">5x</span>
|
|
894
|
+
<span class="cline-any cline-yes">5x</span>
|
|
895
|
+
<span class="cline-any cline-yes">5x</span>
|
|
896
|
+
<span class="cline-any cline-yes">5x</span>
|
|
897
|
+
<span class="cline-any cline-yes">5x</span>
|
|
898
|
+
<span class="cline-any cline-yes">5x</span>
|
|
899
|
+
<span class="cline-any cline-yes">5x</span>
|
|
900
|
+
<span class="cline-any cline-yes">5x</span>
|
|
901
|
+
<span class="cline-any cline-yes">5x</span>
|
|
902
|
+
<span class="cline-any cline-yes">5x</span>
|
|
903
|
+
<span class="cline-any cline-yes">5x</span>
|
|
904
|
+
<span class="cline-any cline-yes">5x</span>
|
|
905
|
+
<span class="cline-any cline-yes">5x</span>
|
|
906
|
+
<span class="cline-any cline-yes">5x</span>
|
|
907
|
+
<span class="cline-any cline-yes">5x</span>
|
|
908
|
+
<span class="cline-any cline-yes">5x</span>
|
|
909
|
+
<span class="cline-any cline-yes">5x</span>
|
|
910
|
+
<span class="cline-any cline-yes">5x</span>
|
|
911
|
+
<span class="cline-any cline-yes">5x</span>
|
|
912
|
+
<span class="cline-any cline-yes">108x</span>
|
|
913
|
+
<span class="cline-any cline-yes">108x</span>
|
|
914
|
+
<span class="cline-any cline-yes">108x</span>
|
|
915
|
+
<span class="cline-any cline-yes">108x</span>
|
|
916
|
+
<span class="cline-any cline-yes">108x</span>
|
|
917
|
+
<span class="cline-any cline-yes">108x</span>
|
|
918
|
+
<span class="cline-any cline-yes">108x</span>
|
|
919
|
+
<span class="cline-any cline-yes">108x</span>
|
|
920
|
+
<span class="cline-any cline-yes">108x</span>
|
|
921
|
+
<span class="cline-any cline-yes">108x</span>
|
|
922
|
+
<span class="cline-any cline-yes">108x</span>
|
|
923
|
+
<span class="cline-any cline-yes">6x</span>
|
|
924
|
+
<span class="cline-any cline-yes">6x</span>
|
|
925
|
+
<span class="cline-any cline-yes">6x</span>
|
|
926
|
+
<span class="cline-any cline-yes">6x</span>
|
|
927
|
+
<span class="cline-any cline-yes">6x</span>
|
|
928
|
+
<span class="cline-any cline-yes">6x</span>
|
|
929
|
+
<span class="cline-any cline-yes">6x</span>
|
|
930
|
+
<span class="cline-any cline-yes">6x</span>
|
|
931
|
+
<span class="cline-any cline-yes">6x</span>
|
|
932
|
+
<span class="cline-any cline-yes">6x</span>
|
|
933
|
+
<span class="cline-any cline-yes">6x</span>
|
|
934
|
+
<span class="cline-any cline-yes">3x</span>
|
|
935
|
+
<span class="cline-any cline-yes">3x</span>
|
|
936
|
+
<span class="cline-any cline-yes">3x</span>
|
|
937
|
+
<span class="cline-any cline-yes">3x</span>
|
|
938
|
+
<span class="cline-any cline-yes">3x</span>
|
|
939
|
+
<span class="cline-any cline-yes">3x</span>
|
|
940
|
+
<span class="cline-any cline-yes">3x</span>
|
|
941
|
+
<span class="cline-any cline-yes">3x</span>
|
|
942
|
+
<span class="cline-any cline-yes">3x</span>
|
|
943
|
+
<span class="cline-any cline-yes">3x</span>
|
|
944
|
+
<span class="cline-any cline-yes">3x</span>
|
|
945
|
+
<span class="cline-any cline-yes">3x</span>
|
|
946
|
+
<span class="cline-any cline-yes">3x</span>
|
|
947
|
+
<span class="cline-any cline-yes">3x</span>
|
|
948
|
+
<span class="cline-any cline-yes">3x</span>
|
|
949
|
+
<span class="cline-any cline-yes">3x</span>
|
|
950
|
+
<span class="cline-any cline-yes">3x</span>
|
|
951
|
+
<span class="cline-any cline-yes">6x</span>
|
|
952
|
+
<span class="cline-any cline-yes">108x</span>
|
|
953
|
+
<span class="cline-any cline-yes">108x</span>
|
|
954
|
+
<span class="cline-any cline-yes">108x</span>
|
|
955
|
+
<span class="cline-any cline-yes">108x</span>
|
|
956
|
+
<span class="cline-any cline-yes">108x</span>
|
|
957
|
+
<span class="cline-any cline-yes">108x</span>
|
|
958
|
+
<span class="cline-any cline-yes">108x</span>
|
|
959
|
+
<span class="cline-any cline-yes">108x</span>
|
|
960
|
+
<span class="cline-any cline-yes">108x</span>
|
|
961
|
+
<span class="cline-any cline-yes">1x</span>
|
|
962
|
+
<span class="cline-any cline-yes">1x</span>
|
|
963
|
+
<span class="cline-any cline-yes">1x</span>
|
|
964
|
+
<span class="cline-any cline-yes">1x</span>
|
|
965
|
+
<span class="cline-any cline-yes">1x</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-no"> </span>
|
|
972
|
+
<span class="cline-any cline-no"> </span>
|
|
973
|
+
<span class="cline-any cline-yes">1x</span>
|
|
974
|
+
<span class="cline-any cline-yes">1x</span>
|
|
975
|
+
<span class="cline-any cline-yes">1x</span>
|
|
976
|
+
<span class="cline-any cline-yes">1x</span>
|
|
977
|
+
<span class="cline-any cline-yes">1x</span>
|
|
978
|
+
<span class="cline-any cline-yes">1x</span>
|
|
979
|
+
<span class="cline-any cline-yes">1x</span>
|
|
980
|
+
<span class="cline-any cline-yes">1x</span>
|
|
981
|
+
<span class="cline-any cline-yes">1x</span>
|
|
982
|
+
<span class="cline-any cline-yes">1x</span>
|
|
983
|
+
<span class="cline-any cline-yes">1x</span>
|
|
984
|
+
<span class="cline-any cline-yes">1x</span>
|
|
985
|
+
<span class="cline-any cline-yes">1x</span>
|
|
986
|
+
<span class="cline-any cline-yes">1x</span>
|
|
987
|
+
<span class="cline-any cline-yes">1x</span>
|
|
988
|
+
<span class="cline-any cline-yes">108x</span>
|
|
989
|
+
<span class="cline-any cline-yes">108x</span>
|
|
990
|
+
<span class="cline-any cline-yes">108x</span>
|
|
991
|
+
<span class="cline-any cline-yes">108x</span>
|
|
992
|
+
<span class="cline-any cline-yes">108x</span>
|
|
993
|
+
<span class="cline-any cline-yes">108x</span>
|
|
994
|
+
<span class="cline-any cline-yes">108x</span>
|
|
995
|
+
<span class="cline-any cline-yes">108x</span>
|
|
996
|
+
<span class="cline-any cline-yes">108x</span>
|
|
997
|
+
<span class="cline-any cline-yes">1x</span>
|
|
998
|
+
<span class="cline-any cline-yes">1x</span>
|
|
999
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1000
|
+
<span class="cline-any cline-no"> </span>
|
|
1001
|
+
<span class="cline-any cline-no"> </span>
|
|
1002
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1003
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1004
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1005
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1006
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1007
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1008
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1009
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1010
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1011
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1012
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1013
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1014
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1015
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1016
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1017
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1018
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1019
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1020
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1021
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1022
|
+
<span class="cline-any cline-no"> </span>
|
|
1023
|
+
<span class="cline-any cline-no"> </span>
|
|
1024
|
+
<span class="cline-any cline-no"> </span>
|
|
1025
|
+
<span class="cline-any cline-no"> </span>
|
|
1026
|
+
<span class="cline-any cline-no"> </span>
|
|
1027
|
+
<span class="cline-any cline-no"> </span>
|
|
1028
|
+
<span class="cline-any cline-no"> </span>
|
|
1029
|
+
<span class="cline-any cline-no"> </span>
|
|
1030
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1031
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1032
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1033
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1034
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1035
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1036
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1037
|
+
<span class="cline-any cline-no"> </span>
|
|
1038
|
+
<span class="cline-any cline-no"> </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-no"> </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-no"> </span>
|
|
1054
|
+
<span class="cline-any cline-no"> </span>
|
|
1055
|
+
<span class="cline-any cline-no"> </span>
|
|
1056
|
+
<span class="cline-any cline-no"> </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-no"> </span>
|
|
1063
|
+
<span class="cline-any cline-no"> </span>
|
|
1064
|
+
<span class="cline-any cline-no"> </span>
|
|
1065
|
+
<span class="cline-any cline-no"> </span>
|
|
1066
|
+
<span class="cline-any cline-no"> </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-yes">108x</span>
|
|
1074
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1075
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1076
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1077
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1078
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1079
|
+
<span class="cline-any cline-no"> </span>
|
|
1080
|
+
<span class="cline-any cline-no"> </span>
|
|
1081
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1082
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1083
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1084
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1085
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1086
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1087
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1088
|
+
<span class="cline-any cline-no"> </span>
|
|
1089
|
+
<span class="cline-any cline-no"> </span>
|
|
1090
|
+
<span class="cline-any cline-no"> </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-no"> </span>
|
|
1098
|
+
<span class="cline-any cline-no"> </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-yes">108x</span>
|
|
1106
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1107
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1108
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1109
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1110
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1111
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1112
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1113
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1114
|
+
<span class="cline-any cline-no"> </span>
|
|
1115
|
+
<span class="cline-any cline-no"> </span>
|
|
1116
|
+
<span class="cline-any cline-no"> </span>
|
|
1117
|
+
<span class="cline-any cline-no"> </span>
|
|
1118
|
+
<span class="cline-any cline-no"> </span>
|
|
1119
|
+
<span class="cline-any cline-no"> </span>
|
|
1120
|
+
<span class="cline-any cline-no"> </span>
|
|
1121
|
+
<span class="cline-any cline-no"> </span>
|
|
1122
|
+
<span class="cline-any cline-no"> </span>
|
|
1123
|
+
<span class="cline-any cline-no"> </span>
|
|
1124
|
+
<span class="cline-any cline-no"> </span>
|
|
1125
|
+
<span class="cline-any cline-no"> </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-yes">108x</span>
|
|
1131
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1132
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1133
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1134
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1135
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1136
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1137
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1138
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1139
|
+
<span class="cline-any cline-yes">22x</span>
|
|
1140
|
+
<span class="cline-any cline-yes">22x</span>
|
|
1141
|
+
<span class="cline-any cline-yes">22x</span>
|
|
1142
|
+
<span class="cline-any cline-yes">22x</span>
|
|
1143
|
+
<span class="cline-any cline-yes">22x</span>
|
|
1144
|
+
<span class="cline-any cline-yes">22x</span>
|
|
1145
|
+
<span class="cline-any cline-yes">22x</span>
|
|
1146
|
+
<span class="cline-any cline-yes">22x</span>
|
|
1147
|
+
<span class="cline-any cline-yes">22x</span>
|
|
1148
|
+
<span class="cline-any cline-yes">22x</span>
|
|
1149
|
+
<span class="cline-any cline-yes">22x</span>
|
|
1150
|
+
<span class="cline-any cline-yes">22x</span>
|
|
1151
|
+
<span class="cline-any cline-yes">22x</span>
|
|
1152
|
+
<span class="cline-any cline-yes">22x</span>
|
|
1153
|
+
<span class="cline-any cline-yes">22x</span>
|
|
1154
|
+
<span class="cline-any cline-yes">22x</span>
|
|
1155
|
+
<span class="cline-any cline-yes">22x</span>
|
|
1156
|
+
<span class="cline-any cline-yes">22x</span>
|
|
1157
|
+
<span class="cline-any cline-yes">22x</span>
|
|
1158
|
+
<span class="cline-any cline-yes">22x</span>
|
|
1159
|
+
<span class="cline-any cline-yes">22x</span>
|
|
1160
|
+
<span class="cline-any cline-yes">22x</span>
|
|
1161
|
+
<span class="cline-any cline-yes">22x</span>
|
|
1162
|
+
<span class="cline-any cline-yes">22x</span>
|
|
1163
|
+
<span class="cline-any cline-yes">22x</span>
|
|
1164
|
+
<span class="cline-any cline-yes">22x</span>
|
|
1165
|
+
<span class="cline-any cline-yes">22x</span>
|
|
1166
|
+
<span class="cline-any cline-yes">22x</span>
|
|
1167
|
+
<span class="cline-any cline-yes">22x</span>
|
|
1168
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1169
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1170
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1171
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1172
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1173
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1174
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1175
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1176
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1177
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1178
|
+
<span class="cline-any cline-no"> </span>
|
|
1179
|
+
<span class="cline-any cline-no"> </span>
|
|
1180
|
+
<span class="cline-any cline-no"> </span>
|
|
1181
|
+
<span class="cline-any cline-no"> </span>
|
|
1182
|
+
<span class="cline-any cline-no"> </span>
|
|
1183
|
+
<span class="cline-any cline-no"> </span>
|
|
1184
|
+
<span class="cline-any cline-no"> </span>
|
|
1185
|
+
<span class="cline-any cline-no"> </span>
|
|
1186
|
+
<span class="cline-any cline-no"> </span>
|
|
1187
|
+
<span class="cline-any cline-no"> </span>
|
|
1188
|
+
<span class="cline-any cline-no"> </span>
|
|
1189
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1190
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1191
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1192
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1193
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1194
|
+
<span class="cline-any cline-yes">103x</span>
|
|
1195
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1196
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1197
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1198
|
+
<span class="cline-any cline-yes">103x</span>
|
|
1199
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1200
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1201
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1202
|
+
<span class="cline-any cline-yes">103x</span>
|
|
1203
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1204
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1205
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1206
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1207
|
+
<span class="cline-any cline-yes">103x</span>
|
|
1208
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1209
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1210
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1211
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1212
|
+
<span class="cline-any cline-yes">103x</span>
|
|
1213
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1214
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1215
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1216
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1217
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1218
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1219
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1220
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1221
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1222
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1223
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1224
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1225
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1226
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1227
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1228
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1229
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1230
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1231
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1232
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1233
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1234
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1235
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1236
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1237
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1238
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1239
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1240
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1241
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1242
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1243
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1244
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1245
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1246
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1247
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1248
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1249
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1250
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1251
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1252
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1253
|
+
<span class="cline-any cline-yes">108x</span>
|
|
1254
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1255
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1256
|
+
<span class="cline-any cline-neutral"> </span></td><td class="text"><pre class="prettyprint lang-js">/**
|
|
1257
|
+
* Complete hook for file handling with:
|
|
1258
|
+
* - Progressive upload to S3 with pre-signed URLs
|
|
1259
|
+
* - Per-file progress tracking
|
|
1260
|
+
* - Type and size validation
|
|
1261
|
+
* - Soft delete (disableFile)
|
|
1262
|
+
* - Multiple file support
|
|
1263
|
+
*/
|
|
1264
|
+
|
|
1265
|
+
import { useState, useCallback, useRef, useMemo } from "react";
|
|
1266
|
+
import { logger } from "../../utils/logger";
|
|
1267
|
+
|
|
1268
|
+
// Import types from dedicated types file
|
|
1269
|
+
import type { FileStatus, FileItem, UseFileUploadOptions, UseFileUploadReturn } from "./types";
|
|
1270
|
+
|
|
1271
|
+
// Import utilities
|
|
1272
|
+
import { generateFileId, extractRelativePath } from "./utils/fileUtils";
|
|
1273
|
+
import { inferContentType } from "./utils/mimeTypes";
|
|
1274
|
+
import { validateFile as validateFileUtil, validateFileCounts } from "./utils/validation";
|
|
1275
|
+
|
|
1276
|
+
// Import services
|
|
1277
|
+
import { generateSignedUploadUrl, uploadToSignedUrl, deleteFile as deleteFileService, getSignedPreviewUrl } from "./services/uploadService";
|
|
1278
|
+
|
|
1279
|
+
// Re-export types for backwards compatibility
|
|
1280
|
+
export type { FileStatus, FileItem, UseFileUploadOptions, UseFileUploadReturn } from "./types";
|
|
1281
|
+
|
|
1282
|
+
/**
|
|
1283
|
+
* Hook for complete file handling with S3 upload
|
|
1284
|
+
*
|
|
1285
|
+
* @example
|
|
1286
|
+
* ```tsx
|
|
1287
|
+
* const {
|
|
1288
|
+
* files,
|
|
1289
|
+
* addFiles,
|
|
1290
|
+
* removeFile,
|
|
1291
|
+
* isUploading,
|
|
1292
|
+
* isValid,
|
|
1293
|
+
* completedS3Keys
|
|
1294
|
+
* } = useFileUpload({
|
|
1295
|
+
* acceptedTypes: ["image/png", "image/jpeg", "application/pdf"],
|
|
1296
|
+
* maxFileSize: 5 * 1024 * 1024, // 5MB
|
|
1297
|
+
* maxFiles: 3,
|
|
1298
|
+
* minFiles: 1
|
|
1299
|
+
* });
|
|
1300
|
+
*
|
|
1301
|
+
* // In form submit
|
|
1302
|
+
* const handleSubmit = async () => {
|
|
1303
|
+
* await waitForUploads(); // Wait for pending uploads
|
|
1304
|
+
* if (!isValid) return;
|
|
1305
|
+
*
|
|
1306
|
+
* await crudify.createItem("documents", {
|
|
1307
|
+
* files: completedS3Keys
|
|
1308
|
+
* });
|
|
1309
|
+
* };
|
|
1310
|
+
* ```
|
|
1311
|
+
*/
|
|
1312
|
+
export const useFileUpload = (options: UseFileUploadOptions = {}): UseFileUploadReturn => {
|
|
1313
|
+
const {
|
|
1314
|
+
acceptedTypes,
|
|
1315
|
+
maxFileSize = 10 * 1024 * 1024, // 10MB default
|
|
1316
|
+
maxFiles,
|
|
1317
|
+
minFiles = 0,
|
|
1318
|
+
visibility = "private",
|
|
1319
|
+
onUploadComplete,
|
|
1320
|
+
onUploadError,
|
|
1321
|
+
onFileRemoved,
|
|
1322
|
+
onFilesChange,
|
|
1323
|
+
mode = "edit", // Default to edit mode for backwards compatibility
|
|
1324
|
+
} = options;
|
|
1325
|
+
|
|
1326
|
+
const [files, setFiles] = useState<FileItem[]>([]);
|
|
1327
|
+
const [isTouched, setIsTouched] = useState(false);
|
|
1328
|
+
const [isSubmitted, setIsSubmitted] = useState(false);
|
|
1329
|
+
const [pendingDeletions, setPendingDeletions] = useState<string[]>([]);
|
|
1330
|
+
const uploadPromisesRef = useRef<Map<string, Promise<void>>>(new Map());
|
|
1331
|
+
|
|
1332
|
+
/**
|
|
1333
|
+
* Marks the field as touched (to show validation errors)
|
|
1334
|
+
*/
|
|
1335
|
+
const markAsTouched = useCallback(() => {
|
|
1336
|
+
setIsTouched(true);
|
|
1337
|
+
}, []);
|
|
1338
|
+
|
|
1339
|
+
/**
|
|
1340
|
+
* Marks the form as submitted (to show all validation errors)
|
|
1341
|
+
*/
|
|
1342
|
+
const markAsSubmitted = useCallback(() => {
|
|
1343
|
+
<span class="cstat-no" title="statement not covered" > setIsSubmitted(true);</span>
|
|
1344
|
+
<span class="cstat-no" title="statement not covered" > setIsTouched(true);</span>
|
|
1345
|
+
}, []);
|
|
1346
|
+
|
|
1347
|
+
/**
|
|
1348
|
+
* Updates a file in the list
|
|
1349
|
+
*/
|
|
1350
|
+
const updateFile = useCallback((fileId: string, updates: Partial<FileItem>) => {
|
|
1351
|
+
setFiles((prev) => {
|
|
1352
|
+
const updated = prev.map((f) => (f.id === fileId ? { ...f, ...updates <span class="branch-0 cbranch-no" title="branch not covered" >} : f))</span>;
|
|
1353
|
+
return updated;
|
|
1354
|
+
});
|
|
1355
|
+
}, []);
|
|
1356
|
+
|
|
1357
|
+
/**
|
|
1358
|
+
* Notifies file changes
|
|
1359
|
+
*/
|
|
1360
|
+
const notifyFilesChange = useCallback(
|
|
1361
|
+
(newFiles: FileItem[]) => {
|
|
1362
|
+
onFilesChange?.(newFiles);
|
|
1363
|
+
},
|
|
1364
|
+
[onFilesChange],
|
|
1365
|
+
);
|
|
1366
|
+
|
|
1367
|
+
/**
|
|
1368
|
+
* Validates a file before upload - using extracted utility
|
|
1369
|
+
*/
|
|
1370
|
+
const validateFile = useCallback((file: File) => validateFileUtil(file, acceptedTypes, maxFileSize), [acceptedTypes, maxFileSize]);
|
|
1371
|
+
|
|
1372
|
+
/**
|
|
1373
|
+
* Uploads a single file to S3 - using extracted service
|
|
1374
|
+
*/
|
|
1375
|
+
const uploadFile = useCallback(
|
|
1376
|
+
async (fileItem: FileItem, file: File): Promise<void> => {
|
|
1377
|
+
try {
|
|
1378
|
+
// Get pre-signed URL using service
|
|
1379
|
+
const { uploadUrl, filePath, publicUrl } = await generateSignedUploadUrl(file.name, file.type, visibility);
|
|
1380
|
+
|
|
1381
|
+
// Update state to uploading
|
|
1382
|
+
updateFile(fileItem.id, { status: "uploading", progress: 0 });
|
|
1383
|
+
|
|
1384
|
+
// Perform upload using service with progress callback
|
|
1385
|
+
await uploadToSignedUrl(file, uploadUrl, {
|
|
1386
|
+
onProgress: <span class="fstat-no" title="function not covered" >(progress) => updateFile(fileItem.id, { progress }),</span>
|
|
1387
|
+
});
|
|
1388
|
+
|
|
1389
|
+
// Mark as completed
|
|
1390
|
+
const completedFile: Partial<FileItem> = {
|
|
1391
|
+
status: "completed",
|
|
1392
|
+
progress: 100,
|
|
1393
|
+
filePath,
|
|
1394
|
+
visibility,
|
|
1395
|
+
publicUrl,
|
|
1396
|
+
file: undefined, // Clear File reference
|
|
1397
|
+
};
|
|
1398
|
+
|
|
1399
|
+
// Update state and notify changes
|
|
1400
|
+
setFiles((prev) => {
|
|
1401
|
+
const updated = prev.map((f) => (f.id === fileItem.id ? { ...f, ...completedFile <span class="branch-0 cbranch-no" title="branch not covered" >} : f))</span>;
|
|
1402
|
+
// Notify file change so the form receives the filePath
|
|
1403
|
+
notifyFilesChange(updated);
|
|
1404
|
+
// Notify upload success
|
|
1405
|
+
const updatedFile = updated.find((f) => f.id === fileItem.id);
|
|
1406
|
+
if (updatedFile) {
|
|
1407
|
+
<span class="branch-0 cbranch-no" title="branch not covered" > onUploadComplete?.(updatedFile);</span>
|
|
1408
|
+
}
|
|
1409
|
+
return updated;
|
|
1410
|
+
});
|
|
1411
|
+
<span class="branch-0 cbranch-no" title="branch not covered" > } catch (error) {</span>
|
|
1412
|
+
<span class="cstat-no" title="statement not covered" > const errorMessage = error instanceof Error ? error.message : "Unknown error";</span>
|
|
1413
|
+
<span class="cstat-no" title="statement not covered" ></span>
|
|
1414
|
+
<span class="cstat-no" title="statement not covered" > updateFile(fileItem.id, {</span>
|
|
1415
|
+
<span class="cstat-no" title="statement not covered" > status: "error",</span>
|
|
1416
|
+
<span class="cstat-no" title="statement not covered" > progress: 0,</span>
|
|
1417
|
+
<span class="cstat-no" title="statement not covered" > errorMessage,</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" > setFiles((prev) => {</span>
|
|
1421
|
+
<span class="cstat-no" title="statement not covered" > const updatedFile = prev.find((f) => f.id === fileItem.id);</span>
|
|
1422
|
+
<span class="cstat-no" title="statement not covered" > if (updatedFile) {</span>
|
|
1423
|
+
<span class="cstat-no" title="statement not covered" > onUploadError?.(updatedFile, errorMessage);</span>
|
|
1424
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1425
|
+
<span class="cstat-no" title="statement not covered" > return prev;</span>
|
|
1426
|
+
<span class="cstat-no" title="statement not covered" > });</span>
|
|
1427
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1428
|
+
},
|
|
1429
|
+
[updateFile, onUploadComplete, onUploadError, visibility, notifyFilesChange],
|
|
1430
|
+
);
|
|
1431
|
+
|
|
1432
|
+
/**
|
|
1433
|
+
* Add files and start upload
|
|
1434
|
+
*/
|
|
1435
|
+
const addFiles = useCallback(
|
|
1436
|
+
async (newFiles: FileList | File[]): Promise<void> => {
|
|
1437
|
+
let fileArray = Array.from(newFiles);
|
|
1438
|
+
|
|
1439
|
+
// Use functional update to get current file count and avoid stale closure
|
|
1440
|
+
let filesToAdd: FileItem[] = [];
|
|
1441
|
+
|
|
1442
|
+
setFiles((prevFiles) => {
|
|
1443
|
+
// Validate file limit using current state
|
|
1444
|
+
// Only count active files (not pendingDeletion or error)
|
|
1445
|
+
if (maxFiles !== undefined) {
|
|
1446
|
+
const activeCount = prevFiles.filter((f) => f.status !== "pendingDeletion" && f.status !== "error").length;
|
|
1447
|
+
const remainingSlots = maxFiles - activeCount;
|
|
1448
|
+
|
|
1449
|
+
if (remainingSlots <= 0) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
|
|
1450
|
+
<span class="cstat-no" title="statement not covered" > logger.warn(`File limit of ${maxFiles} already reached`);</span>
|
|
1451
|
+
<span class="cstat-no" title="statement not covered" > return prevFiles;</span>
|
|
1452
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1453
|
+
|
|
1454
|
+
if (fileArray.length > remainingSlots) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
|
|
1455
|
+
<span class="cstat-no" title="statement not covered" > fileArray = fileArray.slice(0, remainingSlots);</span>
|
|
1456
|
+
<span class="cstat-no" title="statement not covered" > logger.warn(`Only ${remainingSlots} files will be added to not exceed limit`);</span>
|
|
1457
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
// Create file items
|
|
1461
|
+
const newFileItems: FileItem[] = [];
|
|
1462
|
+
|
|
1463
|
+
for (const file of fileArray) {
|
|
1464
|
+
// Validate file
|
|
1465
|
+
const validation = validateFile(file);
|
|
1466
|
+
|
|
1467
|
+
const fileItem: FileItem = {
|
|
1468
|
+
id: generateFileId(),
|
|
1469
|
+
name: file.name,
|
|
1470
|
+
size: file.size,
|
|
1471
|
+
contentType: file.type,
|
|
1472
|
+
status: validation.valid ? <span class="branch-0 cbranch-no" title="branch not covered" >"pending" : "error",</span>
|
|
1473
|
+
progress: 0,
|
|
1474
|
+
createdAt: Date.now(),
|
|
1475
|
+
file: validation.valid ? <span class="branch-0 cbranch-no" title="branch not covered" >file : undefined,</span>
|
|
1476
|
+
errorMessage: validation.error,
|
|
1477
|
+
isExisting: false, // Mark as new file (not from server)
|
|
1478
|
+
};
|
|
1479
|
+
|
|
1480
|
+
newFileItems.push(fileItem);
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
filesToAdd = newFileItems;
|
|
1484
|
+
const updated = [...prevFiles, ...newFileItems];
|
|
1485
|
+
notifyFilesChange(updated);
|
|
1486
|
+
return updated;
|
|
1487
|
+
});
|
|
1488
|
+
|
|
1489
|
+
// Start uploads in parallel for valid files (after state update)
|
|
1490
|
+
// Use setTimeout to ensure state has been updated
|
|
1491
|
+
setTimeout(() => {
|
|
1492
|
+
const validFiles = filesToAdd.filter((f) => f.status === "pending" && f.file);
|
|
1493
|
+
|
|
1494
|
+
for (const fileItem of validFiles) {
|
|
1495
|
+
if (fileItem.file) {
|
|
1496
|
+
const uploadPromise = uploadFile(fileItem, fileItem.file);
|
|
1497
|
+
uploadPromisesRef.current.set(fileItem.id, uploadPromise);
|
|
1498
|
+
|
|
1499
|
+
// Clean from list when finished
|
|
1500
|
+
uploadPromise.finally(() => {
|
|
1501
|
+
uploadPromisesRef.current.delete(fileItem.id);
|
|
1502
|
+
});
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
}, 0);
|
|
1506
|
+
},
|
|
1507
|
+
[maxFiles, validateFile, uploadFile, notifyFilesChange],
|
|
1508
|
+
);
|
|
1509
|
+
|
|
1510
|
+
/**
|
|
1511
|
+
* Remove file - behavior depends on mode and whether file is existing
|
|
1512
|
+
* - CREATE mode: always needs confirmation, then delete immediately
|
|
1513
|
+
* - EDIT mode + existing file: mark as pendingDeletion (delete on form success)
|
|
1514
|
+
* - EDIT mode + new file: needs confirmation, then delete immediately
|
|
1515
|
+
*/
|
|
1516
|
+
const removeFile = useCallback(
|
|
1517
|
+
async (fileId: string): Promise<{ needsConfirmation: boolean; isExisting: boolean }> => {
|
|
1518
|
+
const file = files.find((f) => f.id === fileId);
|
|
1519
|
+
if (!file) <span class="branch-0 cbranch-no" title="branch not covered" >return { needsConfirmation: false, isExisting: false };</span>
|
|
1520
|
+
|
|
1521
|
+
// Determine if this is an existing file (loaded from server)
|
|
1522
|
+
const isExisting = file.isExisting === true;
|
|
1523
|
+
|
|
1524
|
+
// In CREATE mode: always need confirmation, then delete immediately
|
|
1525
|
+
// In EDIT mode:
|
|
1526
|
+
// - Existing file: mark as pendingDeletion (no confirmation needed, can restore)
|
|
1527
|
+
// - New file: needs confirmation, then delete immediately
|
|
1528
|
+
if (mode === "create" || !isExisting) {
|
|
1529
|
+
// Return that confirmation is needed - component will show popup
|
|
1530
|
+
return { needsConfirmation: true, isExisting };
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
// EDIT mode with existing file: mark as pendingDeletion
|
|
1534
|
+
setPendingDeletions((prev) => [...prev, fileId]);
|
|
1535
|
+
|
|
1536
|
+
// Update file status to pendingDeletion
|
|
1537
|
+
setFiles((prev) => {
|
|
1538
|
+
const updated = prev.map((f) => (f.id === fileId ? { ...f, status: "pendingDeletion" as FileStatus <span class="branch-0 cbranch-no" title="branch not covered" >} : f))</span>;
|
|
1539
|
+
// Notify change - exclude files pending deletion from the list
|
|
1540
|
+
const activeFilesFiltered = updated.filter((f) => f.status !== "pendingDeletion");
|
|
1541
|
+
notifyFilesChange(activeFilesFiltered);
|
|
1542
|
+
return updated;
|
|
1543
|
+
});
|
|
1544
|
+
|
|
1545
|
+
return { needsConfirmation: false, isExisting };
|
|
1546
|
+
},
|
|
1547
|
+
[files, mode, notifyFilesChange],
|
|
1548
|
+
);
|
|
1549
|
+
|
|
1550
|
+
/**
|
|
1551
|
+
* Delete a file immediately from the server - using extracted service
|
|
1552
|
+
* Used for new files (not yet saved in DB) or in CREATE mode
|
|
1553
|
+
*/
|
|
1554
|
+
const deleteFileImmediately = useCallback(
|
|
1555
|
+
async (fileId: string): Promise<{ success: boolean; error?: string }> => {
|
|
1556
|
+
const file = files.find((f) => f.id === fileId);
|
|
1557
|
+
if (!file) <span class="branch-0 cbranch-no" title="branch not covered" >return { success: false, error: "File not found" };</span>
|
|
1558
|
+
|
|
1559
|
+
// If file has no filePath (never uploaded), just remove from state
|
|
1560
|
+
if (!file.filePath) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
|
|
1561
|
+
<span class="cstat-no" title="statement not covered" > setFiles((prev) => {</span>
|
|
1562
|
+
<span class="cstat-no" title="statement not covered" > const updated = prev.filter((f) => f.id !== fileId);</span>
|
|
1563
|
+
<span class="cstat-no" title="statement not covered" > notifyFilesChange(updated);</span>
|
|
1564
|
+
<span class="cstat-no" title="statement not covered" > return updated;</span>
|
|
1565
|
+
<span class="cstat-no" title="statement not covered" > });</span>
|
|
1566
|
+
<span class="cstat-no" title="statement not covered" > return { success: true };</span>
|
|
1567
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1568
|
+
|
|
1569
|
+
// Delete from server using service
|
|
1570
|
+
const result = await deleteFileService(file.filePath);
|
|
1571
|
+
|
|
1572
|
+
if (result.success) {
|
|
1573
|
+
setFiles((prev) => {
|
|
1574
|
+
const updated = prev.filter((f) => f.id !== fileId);
|
|
1575
|
+
notifyFilesChange(updated);
|
|
1576
|
+
return updated;
|
|
1577
|
+
});
|
|
1578
|
+
<span class="branch-0 cbranch-no" title="branch not covered" > onFileRemoved?.(file);</span>
|
|
1579
|
+
return { success: true };
|
|
1580
|
+
<span class="branch-0 cbranch-no" title="branch not covered" > }</span>
|
|
1581
|
+
return { success: false, error: result.error || "Failed to delete file" };
|
|
1582
|
+
},
|
|
1583
|
+
[files, notifyFilesChange, onFileRemoved],
|
|
1584
|
+
);
|
|
1585
|
+
|
|
1586
|
+
/**
|
|
1587
|
+
* Restore a single file that was marked for deletion
|
|
1588
|
+
* Only allows restoring existing files (files loaded from server)
|
|
1589
|
+
*/
|
|
1590
|
+
const restoreFile = useCallback(
|
|
1591
|
+
(fileId: string): boolean => {
|
|
1592
|
+
const file = files.find((f) => f.id === fileId);
|
|
1593
|
+
// Only allow restoring existing files
|
|
1594
|
+
if (!file || !file.isExisting) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
|
|
1595
|
+
<span class="cstat-no" title="statement not covered" > return false;</span>
|
|
1596
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1597
|
+
|
|
1598
|
+
// Remove from pending deletions
|
|
1599
|
+
setPendingDeletions((prev) => prev.filter((id) => id !== fileId));
|
|
1600
|
+
|
|
1601
|
+
// Restore file status to completed
|
|
1602
|
+
setFiles((prev) => {
|
|
1603
|
+
const updated = prev.map((f) => (f.id === fileId ? { ...f, status: "completed" as FileStatus <span class="branch-0 cbranch-no" title="branch not covered" >} : f))</span>;
|
|
1604
|
+
notifyFilesChange(updated);
|
|
1605
|
+
return updated;
|
|
1606
|
+
});
|
|
1607
|
+
|
|
1608
|
+
return true;
|
|
1609
|
+
},
|
|
1610
|
+
[files, notifyFilesChange],
|
|
1611
|
+
);
|
|
1612
|
+
|
|
1613
|
+
/**
|
|
1614
|
+
* Restore all files that were marked for deletion
|
|
1615
|
+
*/
|
|
1616
|
+
const restorePendingDeletions = useCallback(() => {
|
|
1617
|
+
<span class="cstat-no" title="statement not covered" > if (pendingDeletions.length === 0) return;</span>
|
|
1618
|
+
<span class="cstat-no" title="statement not covered" ></span>
|
|
1619
|
+
<span class="cstat-no" title="statement not covered" > setFiles((prev) => {</span>
|
|
1620
|
+
<span class="cstat-no" title="statement not covered" > const updated = prev.map((f) => (pendingDeletions.includes(f.id) ? { ...f, status: "completed" as FileStatus } : f));</span>
|
|
1621
|
+
<span class="cstat-no" title="statement not covered" > notifyFilesChange(updated);</span>
|
|
1622
|
+
<span class="cstat-no" title="statement not covered" > return updated;</span>
|
|
1623
|
+
<span class="cstat-no" title="statement not covered" > });</span>
|
|
1624
|
+
<span class="cstat-no" title="statement not covered" > setPendingDeletions([]);</span>
|
|
1625
|
+
}, [pendingDeletions, notifyFilesChange]);
|
|
1626
|
+
|
|
1627
|
+
/**
|
|
1628
|
+
* Execute all pending deletions (call this on form submit) - using extracted service
|
|
1629
|
+
* This actually deletes the files from the server
|
|
1630
|
+
*/
|
|
1631
|
+
const commitDeletions = useCallback(async (): Promise<{ success: boolean; errors: string[] }> => {
|
|
1632
|
+
<span class="cstat-no" title="statement not covered" > if (pendingDeletions.length === 0) {</span>
|
|
1633
|
+
<span class="cstat-no" title="statement not covered" > return { success: true, errors: [] };</span>
|
|
1634
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1635
|
+
<span class="cstat-no" title="statement not covered" ></span>
|
|
1636
|
+
<span class="cstat-no" title="statement not covered" > const errors: string[] = [];</span>
|
|
1637
|
+
<span class="cstat-no" title="statement not covered" > const successfulDeletions: string[] = [];</span>
|
|
1638
|
+
<span class="cstat-no" title="statement not covered" ></span>
|
|
1639
|
+
<span class="cstat-no" title="statement not covered" > for (const fileId of pendingDeletions) {</span>
|
|
1640
|
+
<span class="cstat-no" title="statement not covered" > const file = files.find((f) => f.id === fileId);</span>
|
|
1641
|
+
<span class="cstat-no" title="statement not covered" > if (!file?.filePath) {</span>
|
|
1642
|
+
<span class="cstat-no" title="statement not covered" > // File without filePath (never uploaded) - just mark as successful</span>
|
|
1643
|
+
<span class="cstat-no" title="statement not covered" > successfulDeletions.push(fileId);</span>
|
|
1644
|
+
<span class="cstat-no" title="statement not covered" > continue;</span>
|
|
1645
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1646
|
+
<span class="cstat-no" title="statement not covered" ></span>
|
|
1647
|
+
<span class="cstat-no" title="statement not covered" > // Use service for deletion</span>
|
|
1648
|
+
<span class="cstat-no" title="statement not covered" > const result = await deleteFileService(file.filePath);</span>
|
|
1649
|
+
<span class="cstat-no" title="statement not covered" ></span>
|
|
1650
|
+
<span class="cstat-no" title="statement not covered" > if (result.success) {</span>
|
|
1651
|
+
<span class="cstat-no" title="statement not covered" > successfulDeletions.push(fileId);</span>
|
|
1652
|
+
<span class="cstat-no" title="statement not covered" > onFileRemoved?.(file);</span>
|
|
1653
|
+
<span class="cstat-no" title="statement not covered" > } else {</span>
|
|
1654
|
+
<span class="cstat-no" title="statement not covered" > errors.push(result.error || `Failed to delete ${file.name}`);</span>
|
|
1655
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1656
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1657
|
+
<span class="cstat-no" title="statement not covered" ></span>
|
|
1658
|
+
<span class="cstat-no" title="statement not covered" > // Remove successfully deleted files from state</span>
|
|
1659
|
+
<span class="cstat-no" title="statement not covered" > if (successfulDeletions.length > 0) {</span>
|
|
1660
|
+
<span class="cstat-no" title="statement not covered" > setFiles((prev) => {</span>
|
|
1661
|
+
<span class="cstat-no" title="statement not covered" > const updated = prev.filter((f) => !successfulDeletions.includes(f.id));</span>
|
|
1662
|
+
<span class="cstat-no" title="statement not covered" > return updated;</span>
|
|
1663
|
+
<span class="cstat-no" title="statement not covered" > });</span>
|
|
1664
|
+
<span class="cstat-no" title="statement not covered" > setPendingDeletions((prev) => prev.filter((id) => !successfulDeletions.includes(id)));</span>
|
|
1665
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1666
|
+
<span class="cstat-no" title="statement not covered" ></span>
|
|
1667
|
+
<span class="cstat-no" title="statement not covered" > return { success: errors.length === 0, errors };</span>
|
|
1668
|
+
}, [files, pendingDeletions, onFileRemoved]);
|
|
1669
|
+
|
|
1670
|
+
/**
|
|
1671
|
+
* Clear all files
|
|
1672
|
+
*/
|
|
1673
|
+
const clearFiles = useCallback(() => {
|
|
1674
|
+
<span class="cstat-no" title="statement not covered" > setFiles([]);</span>
|
|
1675
|
+
<span class="cstat-no" title="statement not covered" > notifyFilesChange([]);</span>
|
|
1676
|
+
}, [notifyFilesChange]);
|
|
1677
|
+
|
|
1678
|
+
/**
|
|
1679
|
+
* Retry upload for failed file
|
|
1680
|
+
*/
|
|
1681
|
+
const retryUpload = useCallback(
|
|
1682
|
+
async (fileId: string): Promise<void> => {
|
|
1683
|
+
<span class="cstat-no" title="statement not covered" > const file = files.find((f) => f.id === fileId);</span>
|
|
1684
|
+
<span class="cstat-no" title="statement not covered" > if (!file || file.status !== "error" || !file.file) {</span>
|
|
1685
|
+
<span class="cstat-no" title="statement not covered" > logger.warn("Cannot retry: file not found or no original file");</span>
|
|
1686
|
+
<span class="cstat-no" title="statement not covered" > return;</span>
|
|
1687
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1688
|
+
<span class="cstat-no" title="statement not covered" ></span>
|
|
1689
|
+
<span class="cstat-no" title="statement not covered" > // Reset state</span>
|
|
1690
|
+
<span class="cstat-no" title="statement not covered" > updateFile(fileId, { status: "pending", progress: 0, errorMessage: undefined });</span>
|
|
1691
|
+
<span class="cstat-no" title="statement not covered" ></span>
|
|
1692
|
+
<span class="cstat-no" title="statement not covered" > // Restart upload</span>
|
|
1693
|
+
<span class="cstat-no" title="statement not covered" > const uploadPromise = uploadFile(file, file.file);</span>
|
|
1694
|
+
<span class="cstat-no" title="statement not covered" > uploadPromisesRef.current.set(fileId, uploadPromise);</span>
|
|
1695
|
+
<span class="cstat-no" title="statement not covered" ></span>
|
|
1696
|
+
<span class="cstat-no" title="statement not covered" > uploadPromise.finally(() => {</span>
|
|
1697
|
+
<span class="cstat-no" title="statement not covered" > uploadPromisesRef.current.delete(fileId);</span>
|
|
1698
|
+
<span class="cstat-no" title="statement not covered" > });</span>
|
|
1699
|
+
<span class="cstat-no" title="statement not covered" > },</span>
|
|
1700
|
+
[files, updateFile, uploadFile],
|
|
1701
|
+
);
|
|
1702
|
+
|
|
1703
|
+
/**
|
|
1704
|
+
* Wait for all uploads to complete
|
|
1705
|
+
* Returns a promise that resolves with the completed file paths
|
|
1706
|
+
* This ensures the caller gets the actual file paths without relying on React state timing
|
|
1707
|
+
*/
|
|
1708
|
+
const waitForUploads = useCallback(async (): Promise<string[]> => {
|
|
1709
|
+
<span class="cstat-no" title="statement not covered" > const promises = Array.from(uploadPromisesRef.current.values());</span>
|
|
1710
|
+
<span class="cstat-no" title="statement not covered" > if (promises.length > 0) {</span>
|
|
1711
|
+
<span class="cstat-no" title="statement not covered" > await Promise.allSettled(promises);</span>
|
|
1712
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1713
|
+
<span class="cstat-no" title="statement not covered" > // Return current completed file paths directly from files state</span>
|
|
1714
|
+
<span class="cstat-no" title="statement not covered" > // We need to get the latest state, so we use a promise that resolves after state update</span>
|
|
1715
|
+
<span class="cstat-no" title="statement not covered" > return new Promise((resolve) => {</span>
|
|
1716
|
+
<span class="cstat-no" title="statement not covered" > // Use setTimeout to ensure we get the state after React has processed updates</span>
|
|
1717
|
+
<span class="cstat-no" title="statement not covered" > setTimeout(() => {</span>
|
|
1718
|
+
<span class="cstat-no" title="statement not covered" > setFiles((currentFiles) => {</span>
|
|
1719
|
+
<span class="cstat-no" title="statement not covered" > const paths = currentFiles.filter((f) => f.status === "completed" && f.filePath).map((f) => f.filePath as string);</span>
|
|
1720
|
+
<span class="cstat-no" title="statement not covered" > resolve(paths);</span>
|
|
1721
|
+
<span class="cstat-no" title="statement not covered" > return currentFiles; // Don't modify state, just read it</span>
|
|
1722
|
+
<span class="cstat-no" title="statement not covered" > });</span>
|
|
1723
|
+
<span class="cstat-no" title="statement not covered" > }, 0);</span>
|
|
1724
|
+
<span class="cstat-no" title="statement not covered" > });</span>
|
|
1725
|
+
}, []);
|
|
1726
|
+
|
|
1727
|
+
/**
|
|
1728
|
+
* Initialize with existing files (for editing)
|
|
1729
|
+
* @param existingFiles - Array of files with filePath (can be relative or full URL with baseUrl)
|
|
1730
|
+
* @param baseUrl - Optional baseUrl to strip from file paths
|
|
1731
|
+
*/
|
|
1732
|
+
const initializeFiles = useCallback(
|
|
1733
|
+
(existingFiles: Array<{ filePath: string; name: string; size?: number; contentType?: string }>, baseUrl?: string) => {
|
|
1734
|
+
const fileItems: FileItem[] = existingFiles.map((ef) => {
|
|
1735
|
+
// IMPORTANT: Extract relative path if it comes with baseUrl
|
|
1736
|
+
// This ensures we always store the relative path (e.g., "public/file.jpg")
|
|
1737
|
+
// and not the full URL (e.g., "https://cdn.example.com/public/file.jpg")
|
|
1738
|
+
const relativePath = extractRelativePath(ef.filePath, baseUrl);
|
|
1739
|
+
|
|
1740
|
+
// Extract visibility from the relative path
|
|
1741
|
+
const fileVisibility = relativePath.includes("/public/") || relativePath.startsWith("public/"<span class="branch-0 cbranch-no" title="branch not covered" >) ? "public" : "</span>private";
|
|
1742
|
+
|
|
1743
|
+
// Infer contentType from extension if not provided
|
|
1744
|
+
const contentType = ef.contentType || inferContentType(ef.name);
|
|
1745
|
+
|
|
1746
|
+
return {
|
|
1747
|
+
id: generateFileId(),
|
|
1748
|
+
name: ef.name,
|
|
1749
|
+
size: ef.size || 0,
|
|
1750
|
+
contentType,
|
|
1751
|
+
status: "completed" as FileStatus,
|
|
1752
|
+
progress: 100,
|
|
1753
|
+
filePath: relativePath, // Always store relative path
|
|
1754
|
+
visibility: fileVisibility,
|
|
1755
|
+
createdAt: Date.now(),
|
|
1756
|
+
isExisting: true, // Mark as existing file (loaded from server)
|
|
1757
|
+
};
|
|
1758
|
+
});
|
|
1759
|
+
|
|
1760
|
+
setFiles(fileItems);
|
|
1761
|
+
notifyFilesChange(fileItems);
|
|
1762
|
+
},
|
|
1763
|
+
[notifyFilesChange],
|
|
1764
|
+
);
|
|
1765
|
+
|
|
1766
|
+
/**
|
|
1767
|
+
* Gets URL for file preview - using extracted service
|
|
1768
|
+
* - Public: returns publicUrl directly
|
|
1769
|
+
* - Private: requests signed URL from backend
|
|
1770
|
+
*/
|
|
1771
|
+
const getPreviewUrl = useCallback(
|
|
1772
|
+
async (fileId: string): Promise<string | null> => {
|
|
1773
|
+
<span class="cstat-no" title="statement not covered" > const file = files.find((f) => f.id === fileId);</span>
|
|
1774
|
+
<span class="cstat-no" title="statement not covered" > if (!file || !file.filePath) return null;</span>
|
|
1775
|
+
<span class="cstat-no" title="statement not covered" ></span>
|
|
1776
|
+
<span class="cstat-no" title="statement not covered" > // If public and already has publicUrl, use it</span>
|
|
1777
|
+
<span class="cstat-no" title="statement not covered" > if (file.visibility === "public" && file.publicUrl) {</span>
|
|
1778
|
+
<span class="cstat-no" title="statement not covered" > return file.publicUrl;</span>
|
|
1779
|
+
<span class="cstat-no" title="statement not covered" > }</span>
|
|
1780
|
+
<span class="cstat-no" title="statement not covered" ></span>
|
|
1781
|
+
<span class="cstat-no" title="statement not covered" > // Request URL from backend using service</span>
|
|
1782
|
+
<span class="cstat-no" title="statement not covered" > return getSignedPreviewUrl(file.filePath, 3600);</span>
|
|
1783
|
+
<span class="cstat-no" title="statement not covered" > },</span>
|
|
1784
|
+
[files],
|
|
1785
|
+
);
|
|
1786
|
+
|
|
1787
|
+
// Derived values with memoization
|
|
1788
|
+
const isUploading = useMemo(() => {
|
|
1789
|
+
return files.some((f) => f.status === "uploading" || f.status === "pending");
|
|
1790
|
+
}, [files]);
|
|
1791
|
+
|
|
1792
|
+
const pendingCount = useMemo(() => {
|
|
1793
|
+
return files.filter((f) => f.status === "uploading" || f.status === "pending").length;
|
|
1794
|
+
}, [files]);
|
|
1795
|
+
|
|
1796
|
+
const completedFilePaths = useMemo(() => {
|
|
1797
|
+
return files.filter((f) => f.status === "completed" && f.filePath).map((f) => f.filePath as string);
|
|
1798
|
+
}, [files]);
|
|
1799
|
+
|
|
1800
|
+
// Active files (excluding pendingDeletion)
|
|
1801
|
+
const activeFiles = useMemo(() => {
|
|
1802
|
+
return files.filter((f) => f.status !== "pendingDeletion");
|
|
1803
|
+
}, [files]);
|
|
1804
|
+
|
|
1805
|
+
// Count of active files (completed, pending, or uploading)
|
|
1806
|
+
const activeFileCount = useMemo(() => {
|
|
1807
|
+
return activeFiles.filter((f) => f.status === "completed" || f.status === "pending" || f.status === "uploading").length;
|
|
1808
|
+
}, [activeFiles]);
|
|
1809
|
+
|
|
1810
|
+
// Validation with i18n keys - using extracted utility
|
|
1811
|
+
const { isValid, validationError, validationErrorKey, validationErrorParams } = useMemo(
|
|
1812
|
+
() => validateFileCounts(activeFiles, minFiles, maxFiles),
|
|
1813
|
+
[activeFiles, minFiles, maxFiles],
|
|
1814
|
+
);
|
|
1815
|
+
|
|
1816
|
+
// Computed value for hasPendingDeletions
|
|
1817
|
+
const hasPendingDeletions = pendingDeletions.length > 0;
|
|
1818
|
+
|
|
1819
|
+
return {
|
|
1820
|
+
files,
|
|
1821
|
+
activeFiles,
|
|
1822
|
+
activeFileCount,
|
|
1823
|
+
isUploading,
|
|
1824
|
+
pendingCount,
|
|
1825
|
+
addFiles,
|
|
1826
|
+
removeFile,
|
|
1827
|
+
deleteFileImmediately,
|
|
1828
|
+
restoreFile,
|
|
1829
|
+
clearFiles,
|
|
1830
|
+
retryUpload,
|
|
1831
|
+
isValid,
|
|
1832
|
+
validationError,
|
|
1833
|
+
validationErrorKey,
|
|
1834
|
+
validationErrorParams,
|
|
1835
|
+
waitForUploads,
|
|
1836
|
+
completedFilePaths,
|
|
1837
|
+
initializeFiles,
|
|
1838
|
+
isTouched,
|
|
1839
|
+
markAsTouched,
|
|
1840
|
+
isSubmitted,
|
|
1841
|
+
markAsSubmitted,
|
|
1842
|
+
getPreviewUrl,
|
|
1843
|
+
pendingDeletions,
|
|
1844
|
+
hasPendingDeletions,
|
|
1845
|
+
commitDeletions,
|
|
1846
|
+
restorePendingDeletions,
|
|
1847
|
+
};
|
|
1848
|
+
};
|
|
1849
|
+
|
|
1850
|
+
export default useFileUpload;
|
|
1851
|
+
</pre></td></tr></table></pre>
|
|
1852
|
+
|
|
1853
|
+
<div class='push'></div><!-- for sticky footer -->
|
|
1854
|
+
</div><!-- /wrapper -->
|
|
1855
|
+
<div class='footer quiet pad2 space-top1 center small'>
|
|
1856
|
+
Code coverage generated by
|
|
1857
|
+
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
1858
|
+
at 2026-01-28T06:22:15.683Z
|
|
1859
|
+
</div>
|
|
1860
|
+
<script src="../../prettify.js"></script>
|
|
1861
|
+
<script>
|
|
1862
|
+
window.onload = function () {
|
|
1863
|
+
prettyPrint();
|
|
1864
|
+
};
|
|
1865
|
+
</script>
|
|
1866
|
+
<script src="../../sorter.js"></script>
|
|
1867
|
+
<script src="../../block-navigation.js"></script>
|
|
1868
|
+
</body>
|
|
1869
|
+
</html>
|
|
1870
|
+
|