strapi-plugin-keycloak-realm-users 1.0.0
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/LICENSE +21 -0
- package/README.md +485 -0
- package/__tests__/constants.test.mjs +207 -0
- package/__tests__/mocks/strapi.mjs +182 -0
- package/__tests__/services/audit-log.test.mjs +283 -0
- package/__tests__/services/keycloak-client.test.mjs +651 -0
- package/__tests__/services/permission.test.mjs +374 -0
- package/__tests__/services/realm.test.mjs +415 -0
- package/__tests__/services/user.test.mjs +487 -0
- package/__tests__/utils/errors.test.mjs +109 -0
- package/admin/src/components/Initializer.jsx +14 -0
- package/admin/src/components/RealmBadge.jsx +17 -0
- package/admin/src/constants.js +14 -0
- package/admin/src/hooks/useAuditLogs.js +142 -0
- package/admin/src/hooks/useKeycloakRoles.js +182 -0
- package/admin/src/hooks/useKeycloakUsers.js +477 -0
- package/admin/src/hooks/useRealmAdmins.js +249 -0
- package/admin/src/hooks/useRealms.js +269 -0
- package/admin/src/index.js +46 -0
- package/admin/src/pages/App.jsx +21 -0
- package/admin/src/pages/AuditPage/index.jsx +213 -0
- package/admin/src/pages/RealmsPage/RealmEditPage.jsx +791 -0
- package/admin/src/pages/RealmsPage/RealmListPage.jsx +231 -0
- package/admin/src/pages/RealmsPage/index.jsx +7 -0
- package/admin/src/pages/UsersPage/UserEditPage.jsx +313 -0
- package/admin/src/pages/UsersPage/UserListPage.jsx +437 -0
- package/admin/src/pages/UsersPage/index.jsx +7 -0
- package/admin/src/pluginId.js +2 -0
- package/admin/src/translations/en.json +77 -0
- package/admin/src/translations/fr.json +77 -0
- package/babel.config.cjs +17 -0
- package/coverage/clover.xml +422 -0
- package/coverage/coverage-final.json +8 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +146 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +210 -0
- package/coverage/lcov-report/src/bootstrap.js.html +346 -0
- package/coverage/lcov-report/src/config/index.html +116 -0
- package/coverage/lcov-report/src/config/index.js.html +106 -0
- package/coverage/lcov-report/src/constants.js.html +850 -0
- package/coverage/lcov-report/src/content-types/audit-log/index.html +116 -0
- package/coverage/lcov-report/src/content-types/audit-log/index.js.html +94 -0
- package/coverage/lcov-report/src/content-types/index.html +116 -0
- package/coverage/lcov-report/src/content-types/index.js.html +112 -0
- package/coverage/lcov-report/src/content-types/realm-admin/index.html +116 -0
- package/coverage/lcov-report/src/content-types/realm-admin/index.js.html +94 -0
- package/coverage/lcov-report/src/content-types/realm-config/index.html +116 -0
- package/coverage/lcov-report/src/content-types/realm-config/index.js.html +94 -0
- package/coverage/lcov-report/src/controllers/audit.js.html +517 -0
- package/coverage/lcov-report/src/controllers/index.html +161 -0
- package/coverage/lcov-report/src/controllers/index.js.html +112 -0
- package/coverage/lcov-report/src/controllers/realm.js.html +1057 -0
- package/coverage/lcov-report/src/controllers/user.js.html +1324 -0
- package/coverage/lcov-report/src/destroy.js.html +100 -0
- package/coverage/lcov-report/src/index.html +116 -0
- package/coverage/lcov-report/src/policies/can-access-realm.js.html +163 -0
- package/coverage/lcov-report/src/policies/index.html +146 -0
- package/coverage/lcov-report/src/policies/index.js.html +106 -0
- package/coverage/lcov-report/src/policies/is-authenticated.js.html +100 -0
- package/coverage/lcov-report/src/register.js.html +106 -0
- package/coverage/lcov-report/src/routes/admin.js.html +844 -0
- package/coverage/lcov-report/src/routes/index.html +131 -0
- package/coverage/lcov-report/src/routes/index.js.html +109 -0
- package/coverage/lcov-report/src/services/audit-log.js.html +673 -0
- package/coverage/lcov-report/src/services/index.html +176 -0
- package/coverage/lcov-report/src/services/index.js.html +124 -0
- package/coverage/lcov-report/src/services/keycloak-client.js.html +2359 -0
- package/coverage/lcov-report/src/services/permission.js.html +955 -0
- package/coverage/lcov-report/src/services/realm.js.html +1207 -0
- package/coverage/lcov-report/src/services/user.js.html +1924 -0
- package/coverage/lcov-report/src/utils/errors.js.html +274 -0
- package/coverage/lcov-report/src/utils/index.html +116 -0
- package/coverage/lcov-report/src/utils/index.js.html +103 -0
- package/coverage/lcov.info +804 -0
- package/dist/_chunks/App-BaKrvCeS.mjs +1975 -0
- package/dist/_chunks/App-DO6syS77.js +1975 -0
- package/dist/_chunks/en-Li-XBDe9.mjs +72 -0
- package/dist/_chunks/en-aCyfgNfr.js +72 -0
- package/dist/_chunks/fr-Cj33Q8jI.js +72 -0
- package/dist/_chunks/fr-vLrXph-Z.mjs +72 -0
- package/dist/_chunks/index-DwDO4-0C.js +69 -0
- package/dist/_chunks/index-jTVd7LdQ.mjs +70 -0
- package/dist/admin/index.js +3 -0
- package/dist/admin/index.mjs +4 -0
- package/dist/server/index.js +3003 -0
- package/dist/server/index.mjs +3004 -0
- package/jest.config.cjs +50 -0
- package/package.json +55 -0
- package/server/src/bootstrap.js +87 -0
- package/server/src/config/index.js +7 -0
- package/server/src/constants.js +255 -0
- package/server/src/content-types/audit-log/index.js +3 -0
- package/server/src/content-types/audit-log/schema.json +61 -0
- package/server/src/content-types/index.js +9 -0
- package/server/src/content-types/realm-admin/index.js +3 -0
- package/server/src/content-types/realm-admin/schema.json +45 -0
- package/server/src/content-types/realm-config/index.js +3 -0
- package/server/src/content-types/realm-config/schema.json +56 -0
- package/server/src/controllers/audit.js +144 -0
- package/server/src/controllers/index.js +9 -0
- package/server/src/controllers/realm.js +324 -0
- package/server/src/controllers/user.js +413 -0
- package/server/src/destroy.js +5 -0
- package/server/src/index.js +21 -0
- package/server/src/policies/can-access-realm.js +26 -0
- package/server/src/policies/index.js +7 -0
- package/server/src/policies/is-authenticated.js +5 -0
- package/server/src/register.js +7 -0
- package/server/src/routes/admin.js +253 -0
- package/server/src/routes/index.js +8 -0
- package/server/src/services/audit-log.js +196 -0
- package/server/src/services/index.js +13 -0
- package/server/src/services/keycloak-client.js +758 -0
- package/server/src/services/permission.js +290 -0
- package/server/src/services/realm.js +374 -0
- package/server/src/services/user.js +613 -0
- package/server/src/utils/errors.js +63 -0
- package/server/src/utils/index.js +6 -0
|
@@ -0,0 +1,1924 @@
|
|
|
1
|
+
|
|
2
|
+
<!doctype html>
|
|
3
|
+
<html lang="en">
|
|
4
|
+
|
|
5
|
+
<head>
|
|
6
|
+
<title>Code coverage report for src/services/user.js</title>
|
|
7
|
+
<meta charset="utf-8" />
|
|
8
|
+
<link rel="stylesheet" href="../../prettify.css" />
|
|
9
|
+
<link rel="stylesheet" href="../../base.css" />
|
|
10
|
+
<link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
|
|
11
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
12
|
+
<style type='text/css'>
|
|
13
|
+
.coverage-summary .sorter {
|
|
14
|
+
background-image: url(../../sort-arrow-sprite.png);
|
|
15
|
+
}
|
|
16
|
+
</style>
|
|
17
|
+
</head>
|
|
18
|
+
|
|
19
|
+
<body>
|
|
20
|
+
<div class='wrapper'>
|
|
21
|
+
<div class='pad1'>
|
|
22
|
+
<h1><a href="../../index.html">All files</a> / <a href="index.html">src/services</a> user.js</h1>
|
|
23
|
+
<div class='clearfix'>
|
|
24
|
+
|
|
25
|
+
<div class='fl pad1y space-right2'>
|
|
26
|
+
<span class="strong">98.95% </span>
|
|
27
|
+
<span class="quiet">Statements</span>
|
|
28
|
+
<span class='fraction'>95/96</span>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
<div class='fl pad1y space-right2'>
|
|
33
|
+
<span class="strong">75% </span>
|
|
34
|
+
<span class="quiet">Branches</span>
|
|
35
|
+
<span class='fraction'>9/12</span>
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
<div class='fl pad1y space-right2'>
|
|
40
|
+
<span class="strong">100% </span>
|
|
41
|
+
<span class="quiet">Functions</span>
|
|
42
|
+
<span class='fraction'>24/24</span>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
<div class='fl pad1y space-right2'>
|
|
47
|
+
<span class="strong">98.94% </span>
|
|
48
|
+
<span class="quiet">Lines</span>
|
|
49
|
+
<span class='fraction'>94/95</span>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
<p class="quiet">
|
|
55
|
+
Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block.
|
|
56
|
+
</p>
|
|
57
|
+
<template id="filterTemplate">
|
|
58
|
+
<div class="quiet">
|
|
59
|
+
Filter:
|
|
60
|
+
<input type="search" id="fileSearch">
|
|
61
|
+
</div>
|
|
62
|
+
</template>
|
|
63
|
+
</div>
|
|
64
|
+
<div class='status-line high'></div>
|
|
65
|
+
<pre><table class="coverage">
|
|
66
|
+
<tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
|
|
67
|
+
<a name='L2'></a><a href='#L2'>2</a>
|
|
68
|
+
<a name='L3'></a><a href='#L3'>3</a>
|
|
69
|
+
<a name='L4'></a><a href='#L4'>4</a>
|
|
70
|
+
<a name='L5'></a><a href='#L5'>5</a>
|
|
71
|
+
<a name='L6'></a><a href='#L6'>6</a>
|
|
72
|
+
<a name='L7'></a><a href='#L7'>7</a>
|
|
73
|
+
<a name='L8'></a><a href='#L8'>8</a>
|
|
74
|
+
<a name='L9'></a><a href='#L9'>9</a>
|
|
75
|
+
<a name='L10'></a><a href='#L10'>10</a>
|
|
76
|
+
<a name='L11'></a><a href='#L11'>11</a>
|
|
77
|
+
<a name='L12'></a><a href='#L12'>12</a>
|
|
78
|
+
<a name='L13'></a><a href='#L13'>13</a>
|
|
79
|
+
<a name='L14'></a><a href='#L14'>14</a>
|
|
80
|
+
<a name='L15'></a><a href='#L15'>15</a>
|
|
81
|
+
<a name='L16'></a><a href='#L16'>16</a>
|
|
82
|
+
<a name='L17'></a><a href='#L17'>17</a>
|
|
83
|
+
<a name='L18'></a><a href='#L18'>18</a>
|
|
84
|
+
<a name='L19'></a><a href='#L19'>19</a>
|
|
85
|
+
<a name='L20'></a><a href='#L20'>20</a>
|
|
86
|
+
<a name='L21'></a><a href='#L21'>21</a>
|
|
87
|
+
<a name='L22'></a><a href='#L22'>22</a>
|
|
88
|
+
<a name='L23'></a><a href='#L23'>23</a>
|
|
89
|
+
<a name='L24'></a><a href='#L24'>24</a>
|
|
90
|
+
<a name='L25'></a><a href='#L25'>25</a>
|
|
91
|
+
<a name='L26'></a><a href='#L26'>26</a>
|
|
92
|
+
<a name='L27'></a><a href='#L27'>27</a>
|
|
93
|
+
<a name='L28'></a><a href='#L28'>28</a>
|
|
94
|
+
<a name='L29'></a><a href='#L29'>29</a>
|
|
95
|
+
<a name='L30'></a><a href='#L30'>30</a>
|
|
96
|
+
<a name='L31'></a><a href='#L31'>31</a>
|
|
97
|
+
<a name='L32'></a><a href='#L32'>32</a>
|
|
98
|
+
<a name='L33'></a><a href='#L33'>33</a>
|
|
99
|
+
<a name='L34'></a><a href='#L34'>34</a>
|
|
100
|
+
<a name='L35'></a><a href='#L35'>35</a>
|
|
101
|
+
<a name='L36'></a><a href='#L36'>36</a>
|
|
102
|
+
<a name='L37'></a><a href='#L37'>37</a>
|
|
103
|
+
<a name='L38'></a><a href='#L38'>38</a>
|
|
104
|
+
<a name='L39'></a><a href='#L39'>39</a>
|
|
105
|
+
<a name='L40'></a><a href='#L40'>40</a>
|
|
106
|
+
<a name='L41'></a><a href='#L41'>41</a>
|
|
107
|
+
<a name='L42'></a><a href='#L42'>42</a>
|
|
108
|
+
<a name='L43'></a><a href='#L43'>43</a>
|
|
109
|
+
<a name='L44'></a><a href='#L44'>44</a>
|
|
110
|
+
<a name='L45'></a><a href='#L45'>45</a>
|
|
111
|
+
<a name='L46'></a><a href='#L46'>46</a>
|
|
112
|
+
<a name='L47'></a><a href='#L47'>47</a>
|
|
113
|
+
<a name='L48'></a><a href='#L48'>48</a>
|
|
114
|
+
<a name='L49'></a><a href='#L49'>49</a>
|
|
115
|
+
<a name='L50'></a><a href='#L50'>50</a>
|
|
116
|
+
<a name='L51'></a><a href='#L51'>51</a>
|
|
117
|
+
<a name='L52'></a><a href='#L52'>52</a>
|
|
118
|
+
<a name='L53'></a><a href='#L53'>53</a>
|
|
119
|
+
<a name='L54'></a><a href='#L54'>54</a>
|
|
120
|
+
<a name='L55'></a><a href='#L55'>55</a>
|
|
121
|
+
<a name='L56'></a><a href='#L56'>56</a>
|
|
122
|
+
<a name='L57'></a><a href='#L57'>57</a>
|
|
123
|
+
<a name='L58'></a><a href='#L58'>58</a>
|
|
124
|
+
<a name='L59'></a><a href='#L59'>59</a>
|
|
125
|
+
<a name='L60'></a><a href='#L60'>60</a>
|
|
126
|
+
<a name='L61'></a><a href='#L61'>61</a>
|
|
127
|
+
<a name='L62'></a><a href='#L62'>62</a>
|
|
128
|
+
<a name='L63'></a><a href='#L63'>63</a>
|
|
129
|
+
<a name='L64'></a><a href='#L64'>64</a>
|
|
130
|
+
<a name='L65'></a><a href='#L65'>65</a>
|
|
131
|
+
<a name='L66'></a><a href='#L66'>66</a>
|
|
132
|
+
<a name='L67'></a><a href='#L67'>67</a>
|
|
133
|
+
<a name='L68'></a><a href='#L68'>68</a>
|
|
134
|
+
<a name='L69'></a><a href='#L69'>69</a>
|
|
135
|
+
<a name='L70'></a><a href='#L70'>70</a>
|
|
136
|
+
<a name='L71'></a><a href='#L71'>71</a>
|
|
137
|
+
<a name='L72'></a><a href='#L72'>72</a>
|
|
138
|
+
<a name='L73'></a><a href='#L73'>73</a>
|
|
139
|
+
<a name='L74'></a><a href='#L74'>74</a>
|
|
140
|
+
<a name='L75'></a><a href='#L75'>75</a>
|
|
141
|
+
<a name='L76'></a><a href='#L76'>76</a>
|
|
142
|
+
<a name='L77'></a><a href='#L77'>77</a>
|
|
143
|
+
<a name='L78'></a><a href='#L78'>78</a>
|
|
144
|
+
<a name='L79'></a><a href='#L79'>79</a>
|
|
145
|
+
<a name='L80'></a><a href='#L80'>80</a>
|
|
146
|
+
<a name='L81'></a><a href='#L81'>81</a>
|
|
147
|
+
<a name='L82'></a><a href='#L82'>82</a>
|
|
148
|
+
<a name='L83'></a><a href='#L83'>83</a>
|
|
149
|
+
<a name='L84'></a><a href='#L84'>84</a>
|
|
150
|
+
<a name='L85'></a><a href='#L85'>85</a>
|
|
151
|
+
<a name='L86'></a><a href='#L86'>86</a>
|
|
152
|
+
<a name='L87'></a><a href='#L87'>87</a>
|
|
153
|
+
<a name='L88'></a><a href='#L88'>88</a>
|
|
154
|
+
<a name='L89'></a><a href='#L89'>89</a>
|
|
155
|
+
<a name='L90'></a><a href='#L90'>90</a>
|
|
156
|
+
<a name='L91'></a><a href='#L91'>91</a>
|
|
157
|
+
<a name='L92'></a><a href='#L92'>92</a>
|
|
158
|
+
<a name='L93'></a><a href='#L93'>93</a>
|
|
159
|
+
<a name='L94'></a><a href='#L94'>94</a>
|
|
160
|
+
<a name='L95'></a><a href='#L95'>95</a>
|
|
161
|
+
<a name='L96'></a><a href='#L96'>96</a>
|
|
162
|
+
<a name='L97'></a><a href='#L97'>97</a>
|
|
163
|
+
<a name='L98'></a><a href='#L98'>98</a>
|
|
164
|
+
<a name='L99'></a><a href='#L99'>99</a>
|
|
165
|
+
<a name='L100'></a><a href='#L100'>100</a>
|
|
166
|
+
<a name='L101'></a><a href='#L101'>101</a>
|
|
167
|
+
<a name='L102'></a><a href='#L102'>102</a>
|
|
168
|
+
<a name='L103'></a><a href='#L103'>103</a>
|
|
169
|
+
<a name='L104'></a><a href='#L104'>104</a>
|
|
170
|
+
<a name='L105'></a><a href='#L105'>105</a>
|
|
171
|
+
<a name='L106'></a><a href='#L106'>106</a>
|
|
172
|
+
<a name='L107'></a><a href='#L107'>107</a>
|
|
173
|
+
<a name='L108'></a><a href='#L108'>108</a>
|
|
174
|
+
<a name='L109'></a><a href='#L109'>109</a>
|
|
175
|
+
<a name='L110'></a><a href='#L110'>110</a>
|
|
176
|
+
<a name='L111'></a><a href='#L111'>111</a>
|
|
177
|
+
<a name='L112'></a><a href='#L112'>112</a>
|
|
178
|
+
<a name='L113'></a><a href='#L113'>113</a>
|
|
179
|
+
<a name='L114'></a><a href='#L114'>114</a>
|
|
180
|
+
<a name='L115'></a><a href='#L115'>115</a>
|
|
181
|
+
<a name='L116'></a><a href='#L116'>116</a>
|
|
182
|
+
<a name='L117'></a><a href='#L117'>117</a>
|
|
183
|
+
<a name='L118'></a><a href='#L118'>118</a>
|
|
184
|
+
<a name='L119'></a><a href='#L119'>119</a>
|
|
185
|
+
<a name='L120'></a><a href='#L120'>120</a>
|
|
186
|
+
<a name='L121'></a><a href='#L121'>121</a>
|
|
187
|
+
<a name='L122'></a><a href='#L122'>122</a>
|
|
188
|
+
<a name='L123'></a><a href='#L123'>123</a>
|
|
189
|
+
<a name='L124'></a><a href='#L124'>124</a>
|
|
190
|
+
<a name='L125'></a><a href='#L125'>125</a>
|
|
191
|
+
<a name='L126'></a><a href='#L126'>126</a>
|
|
192
|
+
<a name='L127'></a><a href='#L127'>127</a>
|
|
193
|
+
<a name='L128'></a><a href='#L128'>128</a>
|
|
194
|
+
<a name='L129'></a><a href='#L129'>129</a>
|
|
195
|
+
<a name='L130'></a><a href='#L130'>130</a>
|
|
196
|
+
<a name='L131'></a><a href='#L131'>131</a>
|
|
197
|
+
<a name='L132'></a><a href='#L132'>132</a>
|
|
198
|
+
<a name='L133'></a><a href='#L133'>133</a>
|
|
199
|
+
<a name='L134'></a><a href='#L134'>134</a>
|
|
200
|
+
<a name='L135'></a><a href='#L135'>135</a>
|
|
201
|
+
<a name='L136'></a><a href='#L136'>136</a>
|
|
202
|
+
<a name='L137'></a><a href='#L137'>137</a>
|
|
203
|
+
<a name='L138'></a><a href='#L138'>138</a>
|
|
204
|
+
<a name='L139'></a><a href='#L139'>139</a>
|
|
205
|
+
<a name='L140'></a><a href='#L140'>140</a>
|
|
206
|
+
<a name='L141'></a><a href='#L141'>141</a>
|
|
207
|
+
<a name='L142'></a><a href='#L142'>142</a>
|
|
208
|
+
<a name='L143'></a><a href='#L143'>143</a>
|
|
209
|
+
<a name='L144'></a><a href='#L144'>144</a>
|
|
210
|
+
<a name='L145'></a><a href='#L145'>145</a>
|
|
211
|
+
<a name='L146'></a><a href='#L146'>146</a>
|
|
212
|
+
<a name='L147'></a><a href='#L147'>147</a>
|
|
213
|
+
<a name='L148'></a><a href='#L148'>148</a>
|
|
214
|
+
<a name='L149'></a><a href='#L149'>149</a>
|
|
215
|
+
<a name='L150'></a><a href='#L150'>150</a>
|
|
216
|
+
<a name='L151'></a><a href='#L151'>151</a>
|
|
217
|
+
<a name='L152'></a><a href='#L152'>152</a>
|
|
218
|
+
<a name='L153'></a><a href='#L153'>153</a>
|
|
219
|
+
<a name='L154'></a><a href='#L154'>154</a>
|
|
220
|
+
<a name='L155'></a><a href='#L155'>155</a>
|
|
221
|
+
<a name='L156'></a><a href='#L156'>156</a>
|
|
222
|
+
<a name='L157'></a><a href='#L157'>157</a>
|
|
223
|
+
<a name='L158'></a><a href='#L158'>158</a>
|
|
224
|
+
<a name='L159'></a><a href='#L159'>159</a>
|
|
225
|
+
<a name='L160'></a><a href='#L160'>160</a>
|
|
226
|
+
<a name='L161'></a><a href='#L161'>161</a>
|
|
227
|
+
<a name='L162'></a><a href='#L162'>162</a>
|
|
228
|
+
<a name='L163'></a><a href='#L163'>163</a>
|
|
229
|
+
<a name='L164'></a><a href='#L164'>164</a>
|
|
230
|
+
<a name='L165'></a><a href='#L165'>165</a>
|
|
231
|
+
<a name='L166'></a><a href='#L166'>166</a>
|
|
232
|
+
<a name='L167'></a><a href='#L167'>167</a>
|
|
233
|
+
<a name='L168'></a><a href='#L168'>168</a>
|
|
234
|
+
<a name='L169'></a><a href='#L169'>169</a>
|
|
235
|
+
<a name='L170'></a><a href='#L170'>170</a>
|
|
236
|
+
<a name='L171'></a><a href='#L171'>171</a>
|
|
237
|
+
<a name='L172'></a><a href='#L172'>172</a>
|
|
238
|
+
<a name='L173'></a><a href='#L173'>173</a>
|
|
239
|
+
<a name='L174'></a><a href='#L174'>174</a>
|
|
240
|
+
<a name='L175'></a><a href='#L175'>175</a>
|
|
241
|
+
<a name='L176'></a><a href='#L176'>176</a>
|
|
242
|
+
<a name='L177'></a><a href='#L177'>177</a>
|
|
243
|
+
<a name='L178'></a><a href='#L178'>178</a>
|
|
244
|
+
<a name='L179'></a><a href='#L179'>179</a>
|
|
245
|
+
<a name='L180'></a><a href='#L180'>180</a>
|
|
246
|
+
<a name='L181'></a><a href='#L181'>181</a>
|
|
247
|
+
<a name='L182'></a><a href='#L182'>182</a>
|
|
248
|
+
<a name='L183'></a><a href='#L183'>183</a>
|
|
249
|
+
<a name='L184'></a><a href='#L184'>184</a>
|
|
250
|
+
<a name='L185'></a><a href='#L185'>185</a>
|
|
251
|
+
<a name='L186'></a><a href='#L186'>186</a>
|
|
252
|
+
<a name='L187'></a><a href='#L187'>187</a>
|
|
253
|
+
<a name='L188'></a><a href='#L188'>188</a>
|
|
254
|
+
<a name='L189'></a><a href='#L189'>189</a>
|
|
255
|
+
<a name='L190'></a><a href='#L190'>190</a>
|
|
256
|
+
<a name='L191'></a><a href='#L191'>191</a>
|
|
257
|
+
<a name='L192'></a><a href='#L192'>192</a>
|
|
258
|
+
<a name='L193'></a><a href='#L193'>193</a>
|
|
259
|
+
<a name='L194'></a><a href='#L194'>194</a>
|
|
260
|
+
<a name='L195'></a><a href='#L195'>195</a>
|
|
261
|
+
<a name='L196'></a><a href='#L196'>196</a>
|
|
262
|
+
<a name='L197'></a><a href='#L197'>197</a>
|
|
263
|
+
<a name='L198'></a><a href='#L198'>198</a>
|
|
264
|
+
<a name='L199'></a><a href='#L199'>199</a>
|
|
265
|
+
<a name='L200'></a><a href='#L200'>200</a>
|
|
266
|
+
<a name='L201'></a><a href='#L201'>201</a>
|
|
267
|
+
<a name='L202'></a><a href='#L202'>202</a>
|
|
268
|
+
<a name='L203'></a><a href='#L203'>203</a>
|
|
269
|
+
<a name='L204'></a><a href='#L204'>204</a>
|
|
270
|
+
<a name='L205'></a><a href='#L205'>205</a>
|
|
271
|
+
<a name='L206'></a><a href='#L206'>206</a>
|
|
272
|
+
<a name='L207'></a><a href='#L207'>207</a>
|
|
273
|
+
<a name='L208'></a><a href='#L208'>208</a>
|
|
274
|
+
<a name='L209'></a><a href='#L209'>209</a>
|
|
275
|
+
<a name='L210'></a><a href='#L210'>210</a>
|
|
276
|
+
<a name='L211'></a><a href='#L211'>211</a>
|
|
277
|
+
<a name='L212'></a><a href='#L212'>212</a>
|
|
278
|
+
<a name='L213'></a><a href='#L213'>213</a>
|
|
279
|
+
<a name='L214'></a><a href='#L214'>214</a>
|
|
280
|
+
<a name='L215'></a><a href='#L215'>215</a>
|
|
281
|
+
<a name='L216'></a><a href='#L216'>216</a>
|
|
282
|
+
<a name='L217'></a><a href='#L217'>217</a>
|
|
283
|
+
<a name='L218'></a><a href='#L218'>218</a>
|
|
284
|
+
<a name='L219'></a><a href='#L219'>219</a>
|
|
285
|
+
<a name='L220'></a><a href='#L220'>220</a>
|
|
286
|
+
<a name='L221'></a><a href='#L221'>221</a>
|
|
287
|
+
<a name='L222'></a><a href='#L222'>222</a>
|
|
288
|
+
<a name='L223'></a><a href='#L223'>223</a>
|
|
289
|
+
<a name='L224'></a><a href='#L224'>224</a>
|
|
290
|
+
<a name='L225'></a><a href='#L225'>225</a>
|
|
291
|
+
<a name='L226'></a><a href='#L226'>226</a>
|
|
292
|
+
<a name='L227'></a><a href='#L227'>227</a>
|
|
293
|
+
<a name='L228'></a><a href='#L228'>228</a>
|
|
294
|
+
<a name='L229'></a><a href='#L229'>229</a>
|
|
295
|
+
<a name='L230'></a><a href='#L230'>230</a>
|
|
296
|
+
<a name='L231'></a><a href='#L231'>231</a>
|
|
297
|
+
<a name='L232'></a><a href='#L232'>232</a>
|
|
298
|
+
<a name='L233'></a><a href='#L233'>233</a>
|
|
299
|
+
<a name='L234'></a><a href='#L234'>234</a>
|
|
300
|
+
<a name='L235'></a><a href='#L235'>235</a>
|
|
301
|
+
<a name='L236'></a><a href='#L236'>236</a>
|
|
302
|
+
<a name='L237'></a><a href='#L237'>237</a>
|
|
303
|
+
<a name='L238'></a><a href='#L238'>238</a>
|
|
304
|
+
<a name='L239'></a><a href='#L239'>239</a>
|
|
305
|
+
<a name='L240'></a><a href='#L240'>240</a>
|
|
306
|
+
<a name='L241'></a><a href='#L241'>241</a>
|
|
307
|
+
<a name='L242'></a><a href='#L242'>242</a>
|
|
308
|
+
<a name='L243'></a><a href='#L243'>243</a>
|
|
309
|
+
<a name='L244'></a><a href='#L244'>244</a>
|
|
310
|
+
<a name='L245'></a><a href='#L245'>245</a>
|
|
311
|
+
<a name='L246'></a><a href='#L246'>246</a>
|
|
312
|
+
<a name='L247'></a><a href='#L247'>247</a>
|
|
313
|
+
<a name='L248'></a><a href='#L248'>248</a>
|
|
314
|
+
<a name='L249'></a><a href='#L249'>249</a>
|
|
315
|
+
<a name='L250'></a><a href='#L250'>250</a>
|
|
316
|
+
<a name='L251'></a><a href='#L251'>251</a>
|
|
317
|
+
<a name='L252'></a><a href='#L252'>252</a>
|
|
318
|
+
<a name='L253'></a><a href='#L253'>253</a>
|
|
319
|
+
<a name='L254'></a><a href='#L254'>254</a>
|
|
320
|
+
<a name='L255'></a><a href='#L255'>255</a>
|
|
321
|
+
<a name='L256'></a><a href='#L256'>256</a>
|
|
322
|
+
<a name='L257'></a><a href='#L257'>257</a>
|
|
323
|
+
<a name='L258'></a><a href='#L258'>258</a>
|
|
324
|
+
<a name='L259'></a><a href='#L259'>259</a>
|
|
325
|
+
<a name='L260'></a><a href='#L260'>260</a>
|
|
326
|
+
<a name='L261'></a><a href='#L261'>261</a>
|
|
327
|
+
<a name='L262'></a><a href='#L262'>262</a>
|
|
328
|
+
<a name='L263'></a><a href='#L263'>263</a>
|
|
329
|
+
<a name='L264'></a><a href='#L264'>264</a>
|
|
330
|
+
<a name='L265'></a><a href='#L265'>265</a>
|
|
331
|
+
<a name='L266'></a><a href='#L266'>266</a>
|
|
332
|
+
<a name='L267'></a><a href='#L267'>267</a>
|
|
333
|
+
<a name='L268'></a><a href='#L268'>268</a>
|
|
334
|
+
<a name='L269'></a><a href='#L269'>269</a>
|
|
335
|
+
<a name='L270'></a><a href='#L270'>270</a>
|
|
336
|
+
<a name='L271'></a><a href='#L271'>271</a>
|
|
337
|
+
<a name='L272'></a><a href='#L272'>272</a>
|
|
338
|
+
<a name='L273'></a><a href='#L273'>273</a>
|
|
339
|
+
<a name='L274'></a><a href='#L274'>274</a>
|
|
340
|
+
<a name='L275'></a><a href='#L275'>275</a>
|
|
341
|
+
<a name='L276'></a><a href='#L276'>276</a>
|
|
342
|
+
<a name='L277'></a><a href='#L277'>277</a>
|
|
343
|
+
<a name='L278'></a><a href='#L278'>278</a>
|
|
344
|
+
<a name='L279'></a><a href='#L279'>279</a>
|
|
345
|
+
<a name='L280'></a><a href='#L280'>280</a>
|
|
346
|
+
<a name='L281'></a><a href='#L281'>281</a>
|
|
347
|
+
<a name='L282'></a><a href='#L282'>282</a>
|
|
348
|
+
<a name='L283'></a><a href='#L283'>283</a>
|
|
349
|
+
<a name='L284'></a><a href='#L284'>284</a>
|
|
350
|
+
<a name='L285'></a><a href='#L285'>285</a>
|
|
351
|
+
<a name='L286'></a><a href='#L286'>286</a>
|
|
352
|
+
<a name='L287'></a><a href='#L287'>287</a>
|
|
353
|
+
<a name='L288'></a><a href='#L288'>288</a>
|
|
354
|
+
<a name='L289'></a><a href='#L289'>289</a>
|
|
355
|
+
<a name='L290'></a><a href='#L290'>290</a>
|
|
356
|
+
<a name='L291'></a><a href='#L291'>291</a>
|
|
357
|
+
<a name='L292'></a><a href='#L292'>292</a>
|
|
358
|
+
<a name='L293'></a><a href='#L293'>293</a>
|
|
359
|
+
<a name='L294'></a><a href='#L294'>294</a>
|
|
360
|
+
<a name='L295'></a><a href='#L295'>295</a>
|
|
361
|
+
<a name='L296'></a><a href='#L296'>296</a>
|
|
362
|
+
<a name='L297'></a><a href='#L297'>297</a>
|
|
363
|
+
<a name='L298'></a><a href='#L298'>298</a>
|
|
364
|
+
<a name='L299'></a><a href='#L299'>299</a>
|
|
365
|
+
<a name='L300'></a><a href='#L300'>300</a>
|
|
366
|
+
<a name='L301'></a><a href='#L301'>301</a>
|
|
367
|
+
<a name='L302'></a><a href='#L302'>302</a>
|
|
368
|
+
<a name='L303'></a><a href='#L303'>303</a>
|
|
369
|
+
<a name='L304'></a><a href='#L304'>304</a>
|
|
370
|
+
<a name='L305'></a><a href='#L305'>305</a>
|
|
371
|
+
<a name='L306'></a><a href='#L306'>306</a>
|
|
372
|
+
<a name='L307'></a><a href='#L307'>307</a>
|
|
373
|
+
<a name='L308'></a><a href='#L308'>308</a>
|
|
374
|
+
<a name='L309'></a><a href='#L309'>309</a>
|
|
375
|
+
<a name='L310'></a><a href='#L310'>310</a>
|
|
376
|
+
<a name='L311'></a><a href='#L311'>311</a>
|
|
377
|
+
<a name='L312'></a><a href='#L312'>312</a>
|
|
378
|
+
<a name='L313'></a><a href='#L313'>313</a>
|
|
379
|
+
<a name='L314'></a><a href='#L314'>314</a>
|
|
380
|
+
<a name='L315'></a><a href='#L315'>315</a>
|
|
381
|
+
<a name='L316'></a><a href='#L316'>316</a>
|
|
382
|
+
<a name='L317'></a><a href='#L317'>317</a>
|
|
383
|
+
<a name='L318'></a><a href='#L318'>318</a>
|
|
384
|
+
<a name='L319'></a><a href='#L319'>319</a>
|
|
385
|
+
<a name='L320'></a><a href='#L320'>320</a>
|
|
386
|
+
<a name='L321'></a><a href='#L321'>321</a>
|
|
387
|
+
<a name='L322'></a><a href='#L322'>322</a>
|
|
388
|
+
<a name='L323'></a><a href='#L323'>323</a>
|
|
389
|
+
<a name='L324'></a><a href='#L324'>324</a>
|
|
390
|
+
<a name='L325'></a><a href='#L325'>325</a>
|
|
391
|
+
<a name='L326'></a><a href='#L326'>326</a>
|
|
392
|
+
<a name='L327'></a><a href='#L327'>327</a>
|
|
393
|
+
<a name='L328'></a><a href='#L328'>328</a>
|
|
394
|
+
<a name='L329'></a><a href='#L329'>329</a>
|
|
395
|
+
<a name='L330'></a><a href='#L330'>330</a>
|
|
396
|
+
<a name='L331'></a><a href='#L331'>331</a>
|
|
397
|
+
<a name='L332'></a><a href='#L332'>332</a>
|
|
398
|
+
<a name='L333'></a><a href='#L333'>333</a>
|
|
399
|
+
<a name='L334'></a><a href='#L334'>334</a>
|
|
400
|
+
<a name='L335'></a><a href='#L335'>335</a>
|
|
401
|
+
<a name='L336'></a><a href='#L336'>336</a>
|
|
402
|
+
<a name='L337'></a><a href='#L337'>337</a>
|
|
403
|
+
<a name='L338'></a><a href='#L338'>338</a>
|
|
404
|
+
<a name='L339'></a><a href='#L339'>339</a>
|
|
405
|
+
<a name='L340'></a><a href='#L340'>340</a>
|
|
406
|
+
<a name='L341'></a><a href='#L341'>341</a>
|
|
407
|
+
<a name='L342'></a><a href='#L342'>342</a>
|
|
408
|
+
<a name='L343'></a><a href='#L343'>343</a>
|
|
409
|
+
<a name='L344'></a><a href='#L344'>344</a>
|
|
410
|
+
<a name='L345'></a><a href='#L345'>345</a>
|
|
411
|
+
<a name='L346'></a><a href='#L346'>346</a>
|
|
412
|
+
<a name='L347'></a><a href='#L347'>347</a>
|
|
413
|
+
<a name='L348'></a><a href='#L348'>348</a>
|
|
414
|
+
<a name='L349'></a><a href='#L349'>349</a>
|
|
415
|
+
<a name='L350'></a><a href='#L350'>350</a>
|
|
416
|
+
<a name='L351'></a><a href='#L351'>351</a>
|
|
417
|
+
<a name='L352'></a><a href='#L352'>352</a>
|
|
418
|
+
<a name='L353'></a><a href='#L353'>353</a>
|
|
419
|
+
<a name='L354'></a><a href='#L354'>354</a>
|
|
420
|
+
<a name='L355'></a><a href='#L355'>355</a>
|
|
421
|
+
<a name='L356'></a><a href='#L356'>356</a>
|
|
422
|
+
<a name='L357'></a><a href='#L357'>357</a>
|
|
423
|
+
<a name='L358'></a><a href='#L358'>358</a>
|
|
424
|
+
<a name='L359'></a><a href='#L359'>359</a>
|
|
425
|
+
<a name='L360'></a><a href='#L360'>360</a>
|
|
426
|
+
<a name='L361'></a><a href='#L361'>361</a>
|
|
427
|
+
<a name='L362'></a><a href='#L362'>362</a>
|
|
428
|
+
<a name='L363'></a><a href='#L363'>363</a>
|
|
429
|
+
<a name='L364'></a><a href='#L364'>364</a>
|
|
430
|
+
<a name='L365'></a><a href='#L365'>365</a>
|
|
431
|
+
<a name='L366'></a><a href='#L366'>366</a>
|
|
432
|
+
<a name='L367'></a><a href='#L367'>367</a>
|
|
433
|
+
<a name='L368'></a><a href='#L368'>368</a>
|
|
434
|
+
<a name='L369'></a><a href='#L369'>369</a>
|
|
435
|
+
<a name='L370'></a><a href='#L370'>370</a>
|
|
436
|
+
<a name='L371'></a><a href='#L371'>371</a>
|
|
437
|
+
<a name='L372'></a><a href='#L372'>372</a>
|
|
438
|
+
<a name='L373'></a><a href='#L373'>373</a>
|
|
439
|
+
<a name='L374'></a><a href='#L374'>374</a>
|
|
440
|
+
<a name='L375'></a><a href='#L375'>375</a>
|
|
441
|
+
<a name='L376'></a><a href='#L376'>376</a>
|
|
442
|
+
<a name='L377'></a><a href='#L377'>377</a>
|
|
443
|
+
<a name='L378'></a><a href='#L378'>378</a>
|
|
444
|
+
<a name='L379'></a><a href='#L379'>379</a>
|
|
445
|
+
<a name='L380'></a><a href='#L380'>380</a>
|
|
446
|
+
<a name='L381'></a><a href='#L381'>381</a>
|
|
447
|
+
<a name='L382'></a><a href='#L382'>382</a>
|
|
448
|
+
<a name='L383'></a><a href='#L383'>383</a>
|
|
449
|
+
<a name='L384'></a><a href='#L384'>384</a>
|
|
450
|
+
<a name='L385'></a><a href='#L385'>385</a>
|
|
451
|
+
<a name='L386'></a><a href='#L386'>386</a>
|
|
452
|
+
<a name='L387'></a><a href='#L387'>387</a>
|
|
453
|
+
<a name='L388'></a><a href='#L388'>388</a>
|
|
454
|
+
<a name='L389'></a><a href='#L389'>389</a>
|
|
455
|
+
<a name='L390'></a><a href='#L390'>390</a>
|
|
456
|
+
<a name='L391'></a><a href='#L391'>391</a>
|
|
457
|
+
<a name='L392'></a><a href='#L392'>392</a>
|
|
458
|
+
<a name='L393'></a><a href='#L393'>393</a>
|
|
459
|
+
<a name='L394'></a><a href='#L394'>394</a>
|
|
460
|
+
<a name='L395'></a><a href='#L395'>395</a>
|
|
461
|
+
<a name='L396'></a><a href='#L396'>396</a>
|
|
462
|
+
<a name='L397'></a><a href='#L397'>397</a>
|
|
463
|
+
<a name='L398'></a><a href='#L398'>398</a>
|
|
464
|
+
<a name='L399'></a><a href='#L399'>399</a>
|
|
465
|
+
<a name='L400'></a><a href='#L400'>400</a>
|
|
466
|
+
<a name='L401'></a><a href='#L401'>401</a>
|
|
467
|
+
<a name='L402'></a><a href='#L402'>402</a>
|
|
468
|
+
<a name='L403'></a><a href='#L403'>403</a>
|
|
469
|
+
<a name='L404'></a><a href='#L404'>404</a>
|
|
470
|
+
<a name='L405'></a><a href='#L405'>405</a>
|
|
471
|
+
<a name='L406'></a><a href='#L406'>406</a>
|
|
472
|
+
<a name='L407'></a><a href='#L407'>407</a>
|
|
473
|
+
<a name='L408'></a><a href='#L408'>408</a>
|
|
474
|
+
<a name='L409'></a><a href='#L409'>409</a>
|
|
475
|
+
<a name='L410'></a><a href='#L410'>410</a>
|
|
476
|
+
<a name='L411'></a><a href='#L411'>411</a>
|
|
477
|
+
<a name='L412'></a><a href='#L412'>412</a>
|
|
478
|
+
<a name='L413'></a><a href='#L413'>413</a>
|
|
479
|
+
<a name='L414'></a><a href='#L414'>414</a>
|
|
480
|
+
<a name='L415'></a><a href='#L415'>415</a>
|
|
481
|
+
<a name='L416'></a><a href='#L416'>416</a>
|
|
482
|
+
<a name='L417'></a><a href='#L417'>417</a>
|
|
483
|
+
<a name='L418'></a><a href='#L418'>418</a>
|
|
484
|
+
<a name='L419'></a><a href='#L419'>419</a>
|
|
485
|
+
<a name='L420'></a><a href='#L420'>420</a>
|
|
486
|
+
<a name='L421'></a><a href='#L421'>421</a>
|
|
487
|
+
<a name='L422'></a><a href='#L422'>422</a>
|
|
488
|
+
<a name='L423'></a><a href='#L423'>423</a>
|
|
489
|
+
<a name='L424'></a><a href='#L424'>424</a>
|
|
490
|
+
<a name='L425'></a><a href='#L425'>425</a>
|
|
491
|
+
<a name='L426'></a><a href='#L426'>426</a>
|
|
492
|
+
<a name='L427'></a><a href='#L427'>427</a>
|
|
493
|
+
<a name='L428'></a><a href='#L428'>428</a>
|
|
494
|
+
<a name='L429'></a><a href='#L429'>429</a>
|
|
495
|
+
<a name='L430'></a><a href='#L430'>430</a>
|
|
496
|
+
<a name='L431'></a><a href='#L431'>431</a>
|
|
497
|
+
<a name='L432'></a><a href='#L432'>432</a>
|
|
498
|
+
<a name='L433'></a><a href='#L433'>433</a>
|
|
499
|
+
<a name='L434'></a><a href='#L434'>434</a>
|
|
500
|
+
<a name='L435'></a><a href='#L435'>435</a>
|
|
501
|
+
<a name='L436'></a><a href='#L436'>436</a>
|
|
502
|
+
<a name='L437'></a><a href='#L437'>437</a>
|
|
503
|
+
<a name='L438'></a><a href='#L438'>438</a>
|
|
504
|
+
<a name='L439'></a><a href='#L439'>439</a>
|
|
505
|
+
<a name='L440'></a><a href='#L440'>440</a>
|
|
506
|
+
<a name='L441'></a><a href='#L441'>441</a>
|
|
507
|
+
<a name='L442'></a><a href='#L442'>442</a>
|
|
508
|
+
<a name='L443'></a><a href='#L443'>443</a>
|
|
509
|
+
<a name='L444'></a><a href='#L444'>444</a>
|
|
510
|
+
<a name='L445'></a><a href='#L445'>445</a>
|
|
511
|
+
<a name='L446'></a><a href='#L446'>446</a>
|
|
512
|
+
<a name='L447'></a><a href='#L447'>447</a>
|
|
513
|
+
<a name='L448'></a><a href='#L448'>448</a>
|
|
514
|
+
<a name='L449'></a><a href='#L449'>449</a>
|
|
515
|
+
<a name='L450'></a><a href='#L450'>450</a>
|
|
516
|
+
<a name='L451'></a><a href='#L451'>451</a>
|
|
517
|
+
<a name='L452'></a><a href='#L452'>452</a>
|
|
518
|
+
<a name='L453'></a><a href='#L453'>453</a>
|
|
519
|
+
<a name='L454'></a><a href='#L454'>454</a>
|
|
520
|
+
<a name='L455'></a><a href='#L455'>455</a>
|
|
521
|
+
<a name='L456'></a><a href='#L456'>456</a>
|
|
522
|
+
<a name='L457'></a><a href='#L457'>457</a>
|
|
523
|
+
<a name='L458'></a><a href='#L458'>458</a>
|
|
524
|
+
<a name='L459'></a><a href='#L459'>459</a>
|
|
525
|
+
<a name='L460'></a><a href='#L460'>460</a>
|
|
526
|
+
<a name='L461'></a><a href='#L461'>461</a>
|
|
527
|
+
<a name='L462'></a><a href='#L462'>462</a>
|
|
528
|
+
<a name='L463'></a><a href='#L463'>463</a>
|
|
529
|
+
<a name='L464'></a><a href='#L464'>464</a>
|
|
530
|
+
<a name='L465'></a><a href='#L465'>465</a>
|
|
531
|
+
<a name='L466'></a><a href='#L466'>466</a>
|
|
532
|
+
<a name='L467'></a><a href='#L467'>467</a>
|
|
533
|
+
<a name='L468'></a><a href='#L468'>468</a>
|
|
534
|
+
<a name='L469'></a><a href='#L469'>469</a>
|
|
535
|
+
<a name='L470'></a><a href='#L470'>470</a>
|
|
536
|
+
<a name='L471'></a><a href='#L471'>471</a>
|
|
537
|
+
<a name='L472'></a><a href='#L472'>472</a>
|
|
538
|
+
<a name='L473'></a><a href='#L473'>473</a>
|
|
539
|
+
<a name='L474'></a><a href='#L474'>474</a>
|
|
540
|
+
<a name='L475'></a><a href='#L475'>475</a>
|
|
541
|
+
<a name='L476'></a><a href='#L476'>476</a>
|
|
542
|
+
<a name='L477'></a><a href='#L477'>477</a>
|
|
543
|
+
<a name='L478'></a><a href='#L478'>478</a>
|
|
544
|
+
<a name='L479'></a><a href='#L479'>479</a>
|
|
545
|
+
<a name='L480'></a><a href='#L480'>480</a>
|
|
546
|
+
<a name='L481'></a><a href='#L481'>481</a>
|
|
547
|
+
<a name='L482'></a><a href='#L482'>482</a>
|
|
548
|
+
<a name='L483'></a><a href='#L483'>483</a>
|
|
549
|
+
<a name='L484'></a><a href='#L484'>484</a>
|
|
550
|
+
<a name='L485'></a><a href='#L485'>485</a>
|
|
551
|
+
<a name='L486'></a><a href='#L486'>486</a>
|
|
552
|
+
<a name='L487'></a><a href='#L487'>487</a>
|
|
553
|
+
<a name='L488'></a><a href='#L488'>488</a>
|
|
554
|
+
<a name='L489'></a><a href='#L489'>489</a>
|
|
555
|
+
<a name='L490'></a><a href='#L490'>490</a>
|
|
556
|
+
<a name='L491'></a><a href='#L491'>491</a>
|
|
557
|
+
<a name='L492'></a><a href='#L492'>492</a>
|
|
558
|
+
<a name='L493'></a><a href='#L493'>493</a>
|
|
559
|
+
<a name='L494'></a><a href='#L494'>494</a>
|
|
560
|
+
<a name='L495'></a><a href='#L495'>495</a>
|
|
561
|
+
<a name='L496'></a><a href='#L496'>496</a>
|
|
562
|
+
<a name='L497'></a><a href='#L497'>497</a>
|
|
563
|
+
<a name='L498'></a><a href='#L498'>498</a>
|
|
564
|
+
<a name='L499'></a><a href='#L499'>499</a>
|
|
565
|
+
<a name='L500'></a><a href='#L500'>500</a>
|
|
566
|
+
<a name='L501'></a><a href='#L501'>501</a>
|
|
567
|
+
<a name='L502'></a><a href='#L502'>502</a>
|
|
568
|
+
<a name='L503'></a><a href='#L503'>503</a>
|
|
569
|
+
<a name='L504'></a><a href='#L504'>504</a>
|
|
570
|
+
<a name='L505'></a><a href='#L505'>505</a>
|
|
571
|
+
<a name='L506'></a><a href='#L506'>506</a>
|
|
572
|
+
<a name='L507'></a><a href='#L507'>507</a>
|
|
573
|
+
<a name='L508'></a><a href='#L508'>508</a>
|
|
574
|
+
<a name='L509'></a><a href='#L509'>509</a>
|
|
575
|
+
<a name='L510'></a><a href='#L510'>510</a>
|
|
576
|
+
<a name='L511'></a><a href='#L511'>511</a>
|
|
577
|
+
<a name='L512'></a><a href='#L512'>512</a>
|
|
578
|
+
<a name='L513'></a><a href='#L513'>513</a>
|
|
579
|
+
<a name='L514'></a><a href='#L514'>514</a>
|
|
580
|
+
<a name='L515'></a><a href='#L515'>515</a>
|
|
581
|
+
<a name='L516'></a><a href='#L516'>516</a>
|
|
582
|
+
<a name='L517'></a><a href='#L517'>517</a>
|
|
583
|
+
<a name='L518'></a><a href='#L518'>518</a>
|
|
584
|
+
<a name='L519'></a><a href='#L519'>519</a>
|
|
585
|
+
<a name='L520'></a><a href='#L520'>520</a>
|
|
586
|
+
<a name='L521'></a><a href='#L521'>521</a>
|
|
587
|
+
<a name='L522'></a><a href='#L522'>522</a>
|
|
588
|
+
<a name='L523'></a><a href='#L523'>523</a>
|
|
589
|
+
<a name='L524'></a><a href='#L524'>524</a>
|
|
590
|
+
<a name='L525'></a><a href='#L525'>525</a>
|
|
591
|
+
<a name='L526'></a><a href='#L526'>526</a>
|
|
592
|
+
<a name='L527'></a><a href='#L527'>527</a>
|
|
593
|
+
<a name='L528'></a><a href='#L528'>528</a>
|
|
594
|
+
<a name='L529'></a><a href='#L529'>529</a>
|
|
595
|
+
<a name='L530'></a><a href='#L530'>530</a>
|
|
596
|
+
<a name='L531'></a><a href='#L531'>531</a>
|
|
597
|
+
<a name='L532'></a><a href='#L532'>532</a>
|
|
598
|
+
<a name='L533'></a><a href='#L533'>533</a>
|
|
599
|
+
<a name='L534'></a><a href='#L534'>534</a>
|
|
600
|
+
<a name='L535'></a><a href='#L535'>535</a>
|
|
601
|
+
<a name='L536'></a><a href='#L536'>536</a>
|
|
602
|
+
<a name='L537'></a><a href='#L537'>537</a>
|
|
603
|
+
<a name='L538'></a><a href='#L538'>538</a>
|
|
604
|
+
<a name='L539'></a><a href='#L539'>539</a>
|
|
605
|
+
<a name='L540'></a><a href='#L540'>540</a>
|
|
606
|
+
<a name='L541'></a><a href='#L541'>541</a>
|
|
607
|
+
<a name='L542'></a><a href='#L542'>542</a>
|
|
608
|
+
<a name='L543'></a><a href='#L543'>543</a>
|
|
609
|
+
<a name='L544'></a><a href='#L544'>544</a>
|
|
610
|
+
<a name='L545'></a><a href='#L545'>545</a>
|
|
611
|
+
<a name='L546'></a><a href='#L546'>546</a>
|
|
612
|
+
<a name='L547'></a><a href='#L547'>547</a>
|
|
613
|
+
<a name='L548'></a><a href='#L548'>548</a>
|
|
614
|
+
<a name='L549'></a><a href='#L549'>549</a>
|
|
615
|
+
<a name='L550'></a><a href='#L550'>550</a>
|
|
616
|
+
<a name='L551'></a><a href='#L551'>551</a>
|
|
617
|
+
<a name='L552'></a><a href='#L552'>552</a>
|
|
618
|
+
<a name='L553'></a><a href='#L553'>553</a>
|
|
619
|
+
<a name='L554'></a><a href='#L554'>554</a>
|
|
620
|
+
<a name='L555'></a><a href='#L555'>555</a>
|
|
621
|
+
<a name='L556'></a><a href='#L556'>556</a>
|
|
622
|
+
<a name='L557'></a><a href='#L557'>557</a>
|
|
623
|
+
<a name='L558'></a><a href='#L558'>558</a>
|
|
624
|
+
<a name='L559'></a><a href='#L559'>559</a>
|
|
625
|
+
<a name='L560'></a><a href='#L560'>560</a>
|
|
626
|
+
<a name='L561'></a><a href='#L561'>561</a>
|
|
627
|
+
<a name='L562'></a><a href='#L562'>562</a>
|
|
628
|
+
<a name='L563'></a><a href='#L563'>563</a>
|
|
629
|
+
<a name='L564'></a><a href='#L564'>564</a>
|
|
630
|
+
<a name='L565'></a><a href='#L565'>565</a>
|
|
631
|
+
<a name='L566'></a><a href='#L566'>566</a>
|
|
632
|
+
<a name='L567'></a><a href='#L567'>567</a>
|
|
633
|
+
<a name='L568'></a><a href='#L568'>568</a>
|
|
634
|
+
<a name='L569'></a><a href='#L569'>569</a>
|
|
635
|
+
<a name='L570'></a><a href='#L570'>570</a>
|
|
636
|
+
<a name='L571'></a><a href='#L571'>571</a>
|
|
637
|
+
<a name='L572'></a><a href='#L572'>572</a>
|
|
638
|
+
<a name='L573'></a><a href='#L573'>573</a>
|
|
639
|
+
<a name='L574'></a><a href='#L574'>574</a>
|
|
640
|
+
<a name='L575'></a><a href='#L575'>575</a>
|
|
641
|
+
<a name='L576'></a><a href='#L576'>576</a>
|
|
642
|
+
<a name='L577'></a><a href='#L577'>577</a>
|
|
643
|
+
<a name='L578'></a><a href='#L578'>578</a>
|
|
644
|
+
<a name='L579'></a><a href='#L579'>579</a>
|
|
645
|
+
<a name='L580'></a><a href='#L580'>580</a>
|
|
646
|
+
<a name='L581'></a><a href='#L581'>581</a>
|
|
647
|
+
<a name='L582'></a><a href='#L582'>582</a>
|
|
648
|
+
<a name='L583'></a><a href='#L583'>583</a>
|
|
649
|
+
<a name='L584'></a><a href='#L584'>584</a>
|
|
650
|
+
<a name='L585'></a><a href='#L585'>585</a>
|
|
651
|
+
<a name='L586'></a><a href='#L586'>586</a>
|
|
652
|
+
<a name='L587'></a><a href='#L587'>587</a>
|
|
653
|
+
<a name='L588'></a><a href='#L588'>588</a>
|
|
654
|
+
<a name='L589'></a><a href='#L589'>589</a>
|
|
655
|
+
<a name='L590'></a><a href='#L590'>590</a>
|
|
656
|
+
<a name='L591'></a><a href='#L591'>591</a>
|
|
657
|
+
<a name='L592'></a><a href='#L592'>592</a>
|
|
658
|
+
<a name='L593'></a><a href='#L593'>593</a>
|
|
659
|
+
<a name='L594'></a><a href='#L594'>594</a>
|
|
660
|
+
<a name='L595'></a><a href='#L595'>595</a>
|
|
661
|
+
<a name='L596'></a><a href='#L596'>596</a>
|
|
662
|
+
<a name='L597'></a><a href='#L597'>597</a>
|
|
663
|
+
<a name='L598'></a><a href='#L598'>598</a>
|
|
664
|
+
<a name='L599'></a><a href='#L599'>599</a>
|
|
665
|
+
<a name='L600'></a><a href='#L600'>600</a>
|
|
666
|
+
<a name='L601'></a><a href='#L601'>601</a>
|
|
667
|
+
<a name='L602'></a><a href='#L602'>602</a>
|
|
668
|
+
<a name='L603'></a><a href='#L603'>603</a>
|
|
669
|
+
<a name='L604'></a><a href='#L604'>604</a>
|
|
670
|
+
<a name='L605'></a><a href='#L605'>605</a>
|
|
671
|
+
<a name='L606'></a><a href='#L606'>606</a>
|
|
672
|
+
<a name='L607'></a><a href='#L607'>607</a>
|
|
673
|
+
<a name='L608'></a><a href='#L608'>608</a>
|
|
674
|
+
<a name='L609'></a><a href='#L609'>609</a>
|
|
675
|
+
<a name='L610'></a><a href='#L610'>610</a>
|
|
676
|
+
<a name='L611'></a><a href='#L611'>611</a>
|
|
677
|
+
<a name='L612'></a><a href='#L612'>612</a>
|
|
678
|
+
<a name='L613'></a><a href='#L613'>613</a>
|
|
679
|
+
<a name='L614'></a><a href='#L614'>614</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral"> </span>
|
|
680
|
+
<span class="cline-any cline-neutral"> </span>
|
|
681
|
+
<span class="cline-any cline-neutral"> </span>
|
|
682
|
+
<span class="cline-any cline-neutral"> </span>
|
|
683
|
+
<span class="cline-any cline-neutral"> </span>
|
|
684
|
+
<span class="cline-any cline-neutral"> </span>
|
|
685
|
+
<span class="cline-any cline-neutral"> </span>
|
|
686
|
+
<span class="cline-any cline-neutral"> </span>
|
|
687
|
+
<span class="cline-any cline-neutral"> </span>
|
|
688
|
+
<span class="cline-any cline-neutral"> </span>
|
|
689
|
+
<span class="cline-any cline-neutral"> </span>
|
|
690
|
+
<span class="cline-any cline-neutral"> </span>
|
|
691
|
+
<span class="cline-any cline-neutral"> </span>
|
|
692
|
+
<span class="cline-any cline-neutral"> </span>
|
|
693
|
+
<span class="cline-any cline-neutral"> </span>
|
|
694
|
+
<span class="cline-any cline-neutral"> </span>
|
|
695
|
+
<span class="cline-any cline-neutral"> </span>
|
|
696
|
+
<span class="cline-any cline-neutral"> </span>
|
|
697
|
+
<span class="cline-any cline-neutral"> </span>
|
|
698
|
+
<span class="cline-any cline-neutral"> </span>
|
|
699
|
+
<span class="cline-any cline-neutral"> </span>
|
|
700
|
+
<span class="cline-any cline-neutral"> </span>
|
|
701
|
+
<span class="cline-any cline-neutral"> </span>
|
|
702
|
+
<span class="cline-any cline-neutral"> </span>
|
|
703
|
+
<span class="cline-any cline-neutral"> </span>
|
|
704
|
+
<span class="cline-any cline-neutral"> </span>
|
|
705
|
+
<span class="cline-any cline-neutral"> </span>
|
|
706
|
+
<span class="cline-any cline-neutral"> </span>
|
|
707
|
+
<span class="cline-any cline-neutral"> </span>
|
|
708
|
+
<span class="cline-any cline-neutral"> </span>
|
|
709
|
+
<span class="cline-any cline-neutral"> </span>
|
|
710
|
+
<span class="cline-any cline-neutral"> </span>
|
|
711
|
+
<span class="cline-any cline-neutral"> </span>
|
|
712
|
+
<span class="cline-any cline-neutral"> </span>
|
|
713
|
+
<span class="cline-any cline-neutral"> </span>
|
|
714
|
+
<span class="cline-any cline-neutral"> </span>
|
|
715
|
+
<span class="cline-any cline-neutral"> </span>
|
|
716
|
+
<span class="cline-any cline-neutral"> </span>
|
|
717
|
+
<span class="cline-any cline-neutral"> </span>
|
|
718
|
+
<span class="cline-any cline-neutral"> </span>
|
|
719
|
+
<span class="cline-any cline-neutral"> </span>
|
|
720
|
+
<span class="cline-any cline-neutral"> </span>
|
|
721
|
+
<span class="cline-any cline-neutral"> </span>
|
|
722
|
+
<span class="cline-any cline-neutral"> </span>
|
|
723
|
+
<span class="cline-any cline-neutral"> </span>
|
|
724
|
+
<span class="cline-any cline-neutral"> </span>
|
|
725
|
+
<span class="cline-any cline-neutral"> </span>
|
|
726
|
+
<span class="cline-any cline-neutral"> </span>
|
|
727
|
+
<span class="cline-any cline-neutral"> </span>
|
|
728
|
+
<span class="cline-any cline-neutral"> </span>
|
|
729
|
+
<span class="cline-any cline-neutral"> </span>
|
|
730
|
+
<span class="cline-any cline-neutral"> </span>
|
|
731
|
+
<span class="cline-any cline-yes">27x</span>
|
|
732
|
+
<span class="cline-any cline-neutral"> </span>
|
|
733
|
+
<span class="cline-any cline-neutral"> </span>
|
|
734
|
+
<span class="cline-any cline-neutral"> </span>
|
|
735
|
+
<span class="cline-any cline-neutral"> </span>
|
|
736
|
+
<span class="cline-any cline-neutral"> </span>
|
|
737
|
+
<span class="cline-any cline-neutral"> </span>
|
|
738
|
+
<span class="cline-any cline-yes">49x</span>
|
|
739
|
+
<span class="cline-any cline-neutral"> </span>
|
|
740
|
+
<span class="cline-any cline-neutral"> </span>
|
|
741
|
+
<span class="cline-any cline-neutral"> </span>
|
|
742
|
+
<span class="cline-any cline-neutral"> </span>
|
|
743
|
+
<span class="cline-any cline-neutral"> </span>
|
|
744
|
+
<span class="cline-any cline-neutral"> </span>
|
|
745
|
+
<span class="cline-any cline-neutral"> </span>
|
|
746
|
+
<span class="cline-any cline-neutral"> </span>
|
|
747
|
+
<span class="cline-any cline-yes">36x</span>
|
|
748
|
+
<span class="cline-any cline-neutral"> </span>
|
|
749
|
+
<span class="cline-any cline-neutral"> </span>
|
|
750
|
+
<span class="cline-any cline-neutral"> </span>
|
|
751
|
+
<span class="cline-any cline-neutral"> </span>
|
|
752
|
+
<span class="cline-any cline-neutral"> </span>
|
|
753
|
+
<span class="cline-any cline-neutral"> </span>
|
|
754
|
+
<span class="cline-any cline-neutral"> </span>
|
|
755
|
+
<span class="cline-any cline-neutral"> </span>
|
|
756
|
+
<span class="cline-any cline-yes">26x</span>
|
|
757
|
+
<span class="cline-any cline-neutral"> </span>
|
|
758
|
+
<span class="cline-any cline-neutral"> </span>
|
|
759
|
+
<span class="cline-any cline-neutral"> </span>
|
|
760
|
+
<span class="cline-any cline-neutral"> </span>
|
|
761
|
+
<span class="cline-any cline-neutral"> </span>
|
|
762
|
+
<span class="cline-any cline-neutral"> </span>
|
|
763
|
+
<span class="cline-any cline-neutral"> </span>
|
|
764
|
+
<span class="cline-any cline-neutral"> </span>
|
|
765
|
+
<span class="cline-any cline-yes">12x</span>
|
|
766
|
+
<span class="cline-any cline-neutral"> </span>
|
|
767
|
+
<span class="cline-any cline-neutral"> </span>
|
|
768
|
+
<span class="cline-any cline-neutral"> </span>
|
|
769
|
+
<span class="cline-any cline-neutral"> </span>
|
|
770
|
+
<span class="cline-any cline-neutral"> </span>
|
|
771
|
+
<span class="cline-any cline-neutral"> </span>
|
|
772
|
+
<span class="cline-any cline-neutral"> </span>
|
|
773
|
+
<span class="cline-any cline-neutral"> </span>
|
|
774
|
+
<span class="cline-any cline-neutral"> </span>
|
|
775
|
+
<span class="cline-any cline-neutral"> </span>
|
|
776
|
+
<span class="cline-any cline-neutral"> </span>
|
|
777
|
+
<span class="cline-any cline-neutral"> </span>
|
|
778
|
+
<span class="cline-any cline-neutral"> </span>
|
|
779
|
+
<span class="cline-any cline-neutral"> </span>
|
|
780
|
+
<span class="cline-any cline-neutral"> </span>
|
|
781
|
+
<span class="cline-any cline-neutral"> </span>
|
|
782
|
+
<span class="cline-any cline-neutral"> </span>
|
|
783
|
+
<span class="cline-any cline-neutral"> </span>
|
|
784
|
+
<span class="cline-any cline-neutral"> </span>
|
|
785
|
+
<span class="cline-any cline-yes">28x</span>
|
|
786
|
+
<span class="cline-any cline-neutral"> </span>
|
|
787
|
+
<span class="cline-any cline-yes">28x</span>
|
|
788
|
+
<span class="cline-any cline-yes">2x</span>
|
|
789
|
+
<span class="cline-any cline-neutral"> </span>
|
|
790
|
+
<span class="cline-any cline-neutral"> </span>
|
|
791
|
+
<span class="cline-any cline-neutral"> </span>
|
|
792
|
+
<span class="cline-any cline-yes">26x</span>
|
|
793
|
+
<span class="cline-any cline-neutral"> </span>
|
|
794
|
+
<span class="cline-any cline-yes">26x</span>
|
|
795
|
+
<span class="cline-any cline-yes">5x</span>
|
|
796
|
+
<span class="cline-any cline-neutral"> </span>
|
|
797
|
+
<span class="cline-any cline-neutral"> </span>
|
|
798
|
+
<span class="cline-any cline-neutral"> </span>
|
|
799
|
+
<span class="cline-any cline-neutral"> </span>
|
|
800
|
+
<span class="cline-any cline-neutral"> </span>
|
|
801
|
+
<span class="cline-any cline-neutral"> </span>
|
|
802
|
+
<span class="cline-any cline-yes">21x</span>
|
|
803
|
+
<span class="cline-any cline-neutral"> </span>
|
|
804
|
+
<span class="cline-any cline-neutral"> </span>
|
|
805
|
+
<span class="cline-any cline-neutral"> </span>
|
|
806
|
+
<span class="cline-any cline-neutral"> </span>
|
|
807
|
+
<span class="cline-any cline-neutral"> </span>
|
|
808
|
+
<span class="cline-any cline-neutral"> </span>
|
|
809
|
+
<span class="cline-any cline-neutral"> </span>
|
|
810
|
+
<span class="cline-any cline-neutral"> </span>
|
|
811
|
+
<span class="cline-any cline-neutral"> </span>
|
|
812
|
+
<span class="cline-any cline-neutral"> </span>
|
|
813
|
+
<span class="cline-any cline-neutral"> </span>
|
|
814
|
+
<span class="cline-any cline-neutral"> </span>
|
|
815
|
+
<span class="cline-any cline-neutral"> </span>
|
|
816
|
+
<span class="cline-any cline-neutral"> </span>
|
|
817
|
+
<span class="cline-any cline-neutral"> </span>
|
|
818
|
+
<span class="cline-any cline-neutral"> </span>
|
|
819
|
+
<span class="cline-any cline-neutral"> </span>
|
|
820
|
+
<span class="cline-any cline-neutral"> </span>
|
|
821
|
+
<span class="cline-any cline-neutral"> </span>
|
|
822
|
+
<span class="cline-any cline-neutral"> </span>
|
|
823
|
+
<span class="cline-any cline-neutral"> </span>
|
|
824
|
+
<span class="cline-any cline-yes">3x</span>
|
|
825
|
+
<span class="cline-any cline-neutral"> </span>
|
|
826
|
+
<span class="cline-any cline-yes">3x</span>
|
|
827
|
+
<span class="cline-any cline-yes">3x</span>
|
|
828
|
+
<span class="cline-any cline-neutral"> </span>
|
|
829
|
+
<span class="cline-any cline-neutral"> </span>
|
|
830
|
+
<span class="cline-any cline-neutral"> </span>
|
|
831
|
+
<span class="cline-any cline-neutral"> </span>
|
|
832
|
+
<span class="cline-any cline-yes">3x</span>
|
|
833
|
+
<span class="cline-any cline-neutral"> </span>
|
|
834
|
+
<span class="cline-any cline-neutral"> </span>
|
|
835
|
+
<span class="cline-any cline-neutral"> </span>
|
|
836
|
+
<span class="cline-any cline-neutral"> </span>
|
|
837
|
+
<span class="cline-any cline-neutral"> </span>
|
|
838
|
+
<span class="cline-any cline-neutral"> </span>
|
|
839
|
+
<span class="cline-any cline-neutral"> </span>
|
|
840
|
+
<span class="cline-any cline-neutral"> </span>
|
|
841
|
+
<span class="cline-any cline-neutral"> </span>
|
|
842
|
+
<span class="cline-any cline-neutral"> </span>
|
|
843
|
+
<span class="cline-any cline-neutral"> </span>
|
|
844
|
+
<span class="cline-any cline-neutral"> </span>
|
|
845
|
+
<span class="cline-any cline-neutral"> </span>
|
|
846
|
+
<span class="cline-any cline-neutral"> </span>
|
|
847
|
+
<span class="cline-any cline-neutral"> </span>
|
|
848
|
+
<span class="cline-any cline-neutral"> </span>
|
|
849
|
+
<span class="cline-any cline-neutral"> </span>
|
|
850
|
+
<span class="cline-any cline-neutral"> </span>
|
|
851
|
+
<span class="cline-any cline-neutral"> </span>
|
|
852
|
+
<span class="cline-any cline-neutral"> </span>
|
|
853
|
+
<span class="cline-any cline-neutral"> </span>
|
|
854
|
+
<span class="cline-any cline-neutral"> </span>
|
|
855
|
+
<span class="cline-any cline-yes">1x</span>
|
|
856
|
+
<span class="cline-any cline-yes">1x</span>
|
|
857
|
+
<span class="cline-any cline-neutral"> </span>
|
|
858
|
+
<span class="cline-any cline-neutral"> </span>
|
|
859
|
+
<span class="cline-any cline-neutral"> </span>
|
|
860
|
+
<span class="cline-any cline-neutral"> </span>
|
|
861
|
+
<span class="cline-any cline-neutral"> </span>
|
|
862
|
+
<span class="cline-any cline-neutral"> </span>
|
|
863
|
+
<span class="cline-any cline-neutral"> </span>
|
|
864
|
+
<span class="cline-any cline-neutral"> </span>
|
|
865
|
+
<span class="cline-any cline-neutral"> </span>
|
|
866
|
+
<span class="cline-any cline-neutral"> </span>
|
|
867
|
+
<span class="cline-any cline-neutral"> </span>
|
|
868
|
+
<span class="cline-any cline-neutral"> </span>
|
|
869
|
+
<span class="cline-any cline-neutral"> </span>
|
|
870
|
+
<span class="cline-any cline-neutral"> </span>
|
|
871
|
+
<span class="cline-any cline-neutral"> </span>
|
|
872
|
+
<span class="cline-any cline-neutral"> </span>
|
|
873
|
+
<span class="cline-any cline-neutral"> </span>
|
|
874
|
+
<span class="cline-any cline-neutral"> </span>
|
|
875
|
+
<span class="cline-any cline-neutral"> </span>
|
|
876
|
+
<span class="cline-any cline-neutral"> </span>
|
|
877
|
+
<span class="cline-any cline-neutral"> </span>
|
|
878
|
+
<span class="cline-any cline-neutral"> </span>
|
|
879
|
+
<span class="cline-any cline-neutral"> </span>
|
|
880
|
+
<span class="cline-any cline-yes">2x</span>
|
|
881
|
+
<span class="cline-any cline-neutral"> </span>
|
|
882
|
+
<span class="cline-any cline-yes">1x</span>
|
|
883
|
+
<span class="cline-any cline-neutral"> </span>
|
|
884
|
+
<span class="cline-any cline-neutral"> </span>
|
|
885
|
+
<span class="cline-any cline-yes">1x</span>
|
|
886
|
+
<span class="cline-any cline-neutral"> </span>
|
|
887
|
+
<span class="cline-any cline-neutral"> </span>
|
|
888
|
+
<span class="cline-any cline-neutral"> </span>
|
|
889
|
+
<span class="cline-any cline-neutral"> </span>
|
|
890
|
+
<span class="cline-any cline-neutral"> </span>
|
|
891
|
+
<span class="cline-any cline-neutral"> </span>
|
|
892
|
+
<span class="cline-any cline-neutral"> </span>
|
|
893
|
+
<span class="cline-any cline-neutral"> </span>
|
|
894
|
+
<span class="cline-any cline-neutral"> </span>
|
|
895
|
+
<span class="cline-any cline-neutral"> </span>
|
|
896
|
+
<span class="cline-any cline-neutral"> </span>
|
|
897
|
+
<span class="cline-any cline-neutral"> </span>
|
|
898
|
+
<span class="cline-any cline-neutral"> </span>
|
|
899
|
+
<span class="cline-any cline-neutral"> </span>
|
|
900
|
+
<span class="cline-any cline-yes">1x</span>
|
|
901
|
+
<span class="cline-any cline-yes">1x</span>
|
|
902
|
+
<span class="cline-any cline-neutral"> </span>
|
|
903
|
+
<span class="cline-any cline-neutral"> </span>
|
|
904
|
+
<span class="cline-any cline-no"> </span>
|
|
905
|
+
<span class="cline-any cline-neutral"> </span>
|
|
906
|
+
<span class="cline-any cline-neutral"> </span>
|
|
907
|
+
<span class="cline-any cline-neutral"> </span>
|
|
908
|
+
<span class="cline-any cline-neutral"> </span>
|
|
909
|
+
<span class="cline-any cline-neutral"> </span>
|
|
910
|
+
<span class="cline-any cline-neutral"> </span>
|
|
911
|
+
<span class="cline-any cline-neutral"> </span>
|
|
912
|
+
<span class="cline-any cline-neutral"> </span>
|
|
913
|
+
<span class="cline-any cline-neutral"> </span>
|
|
914
|
+
<span class="cline-any cline-neutral"> </span>
|
|
915
|
+
<span class="cline-any cline-neutral"> </span>
|
|
916
|
+
<span class="cline-any cline-neutral"> </span>
|
|
917
|
+
<span class="cline-any cline-neutral"> </span>
|
|
918
|
+
<span class="cline-any cline-neutral"> </span>
|
|
919
|
+
<span class="cline-any cline-neutral"> </span>
|
|
920
|
+
<span class="cline-any cline-neutral"> </span>
|
|
921
|
+
<span class="cline-any cline-neutral"> </span>
|
|
922
|
+
<span class="cline-any cline-neutral"> </span>
|
|
923
|
+
<span class="cline-any cline-neutral"> </span>
|
|
924
|
+
<span class="cline-any cline-neutral"> </span>
|
|
925
|
+
<span class="cline-any cline-yes">1x</span>
|
|
926
|
+
<span class="cline-any cline-neutral"> </span>
|
|
927
|
+
<span class="cline-any cline-neutral"> </span>
|
|
928
|
+
<span class="cline-any cline-yes">1x</span>
|
|
929
|
+
<span class="cline-any cline-neutral"> </span>
|
|
930
|
+
<span class="cline-any cline-yes">1x</span>
|
|
931
|
+
<span class="cline-any cline-neutral"> </span>
|
|
932
|
+
<span class="cline-any cline-yes">1x</span>
|
|
933
|
+
<span class="cline-any cline-neutral"> </span>
|
|
934
|
+
<span class="cline-any cline-neutral"> </span>
|
|
935
|
+
<span class="cline-any cline-neutral"> </span>
|
|
936
|
+
<span class="cline-any cline-neutral"> </span>
|
|
937
|
+
<span class="cline-any cline-neutral"> </span>
|
|
938
|
+
<span class="cline-any cline-neutral"> </span>
|
|
939
|
+
<span class="cline-any cline-neutral"> </span>
|
|
940
|
+
<span class="cline-any cline-neutral"> </span>
|
|
941
|
+
<span class="cline-any cline-neutral"> </span>
|
|
942
|
+
<span class="cline-any cline-yes">1x</span>
|
|
943
|
+
<span class="cline-any cline-neutral"> </span>
|
|
944
|
+
<span class="cline-any cline-neutral"> </span>
|
|
945
|
+
<span class="cline-any cline-neutral"> </span>
|
|
946
|
+
<span class="cline-any cline-neutral"> </span>
|
|
947
|
+
<span class="cline-any cline-neutral"> </span>
|
|
948
|
+
<span class="cline-any cline-neutral"> </span>
|
|
949
|
+
<span class="cline-any cline-neutral"> </span>
|
|
950
|
+
<span class="cline-any cline-neutral"> </span>
|
|
951
|
+
<span class="cline-any cline-neutral"> </span>
|
|
952
|
+
<span class="cline-any cline-neutral"> </span>
|
|
953
|
+
<span class="cline-any cline-neutral"> </span>
|
|
954
|
+
<span class="cline-any cline-neutral"> </span>
|
|
955
|
+
<span class="cline-any cline-neutral"> </span>
|
|
956
|
+
<span class="cline-any cline-neutral"> </span>
|
|
957
|
+
<span class="cline-any cline-yes">1x</span>
|
|
958
|
+
<span class="cline-any cline-neutral"> </span>
|
|
959
|
+
<span class="cline-any cline-neutral"> </span>
|
|
960
|
+
<span class="cline-any cline-yes">1x</span>
|
|
961
|
+
<span class="cline-any cline-neutral"> </span>
|
|
962
|
+
<span class="cline-any cline-yes">1x</span>
|
|
963
|
+
<span class="cline-any cline-neutral"> </span>
|
|
964
|
+
<span class="cline-any cline-yes">1x</span>
|
|
965
|
+
<span class="cline-any cline-neutral"> </span>
|
|
966
|
+
<span class="cline-any cline-neutral"> </span>
|
|
967
|
+
<span class="cline-any cline-neutral"> </span>
|
|
968
|
+
<span class="cline-any cline-neutral"> </span>
|
|
969
|
+
<span class="cline-any cline-neutral"> </span>
|
|
970
|
+
<span class="cline-any cline-neutral"> </span>
|
|
971
|
+
<span class="cline-any cline-neutral"> </span>
|
|
972
|
+
<span class="cline-any cline-neutral"> </span>
|
|
973
|
+
<span class="cline-any cline-neutral"> </span>
|
|
974
|
+
<span class="cline-any cline-yes">1x</span>
|
|
975
|
+
<span class="cline-any cline-neutral"> </span>
|
|
976
|
+
<span class="cline-any cline-neutral"> </span>
|
|
977
|
+
<span class="cline-any cline-neutral"> </span>
|
|
978
|
+
<span class="cline-any cline-neutral"> </span>
|
|
979
|
+
<span class="cline-any cline-neutral"> </span>
|
|
980
|
+
<span class="cline-any cline-neutral"> </span>
|
|
981
|
+
<span class="cline-any cline-neutral"> </span>
|
|
982
|
+
<span class="cline-any cline-neutral"> </span>
|
|
983
|
+
<span class="cline-any cline-neutral"> </span>
|
|
984
|
+
<span class="cline-any cline-neutral"> </span>
|
|
985
|
+
<span class="cline-any cline-neutral"> </span>
|
|
986
|
+
<span class="cline-any cline-neutral"> </span>
|
|
987
|
+
<span class="cline-any cline-neutral"> </span>
|
|
988
|
+
<span class="cline-any cline-neutral"> </span>
|
|
989
|
+
<span class="cline-any cline-neutral"> </span>
|
|
990
|
+
<span class="cline-any cline-neutral"> </span>
|
|
991
|
+
<span class="cline-any cline-neutral"> </span>
|
|
992
|
+
<span class="cline-any cline-neutral"> </span>
|
|
993
|
+
<span class="cline-any cline-yes">2x</span>
|
|
994
|
+
<span class="cline-any cline-neutral"> </span>
|
|
995
|
+
<span class="cline-any cline-yes">1x</span>
|
|
996
|
+
<span class="cline-any cline-yes">1x</span>
|
|
997
|
+
<span class="cline-any cline-neutral"> </span>
|
|
998
|
+
<span class="cline-any cline-yes">1x</span>
|
|
999
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1000
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1001
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1002
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1003
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1004
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1005
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1006
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1007
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1008
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1009
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1010
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1011
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1012
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1013
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1014
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1015
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1016
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1017
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1018
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1019
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1020
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1021
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1022
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1023
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1024
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1025
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1026
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1027
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1028
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1029
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1030
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1031
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1032
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1033
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1034
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1035
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1036
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1037
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1038
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1039
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1040
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1041
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1042
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1043
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1044
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1045
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1046
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1047
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1048
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1049
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1050
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1051
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1052
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1053
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1054
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1055
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1056
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1057
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1058
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1059
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1060
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1061
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1062
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1063
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1064
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1065
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1066
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1067
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1068
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1069
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1070
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1071
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1072
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1073
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1074
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1075
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1076
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1077
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1078
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1079
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1080
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1081
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1082
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1083
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1084
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1085
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1086
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1087
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1088
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1089
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1090
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1091
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1092
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1093
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1094
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1095
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1096
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1097
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1098
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1099
|
+
<span class="cline-any cline-yes">2x</span>
|
|
1100
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1101
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1102
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1103
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1104
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1105
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1106
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1107
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1108
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1109
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1110
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1111
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1112
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1113
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1114
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1115
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1116
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1117
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1118
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1119
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1120
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1121
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1122
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1123
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1124
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1125
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1126
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1127
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1128
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1129
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1130
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1131
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1132
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1133
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1134
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1135
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1136
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1137
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1138
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1139
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1140
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1141
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1142
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1143
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1144
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1145
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1146
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1147
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1148
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1149
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1150
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1151
|
+
<span class="cline-any cline-yes">2x</span>
|
|
1152
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1153
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1154
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1155
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1156
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1157
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1158
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1159
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1160
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1161
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1162
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1163
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1164
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1165
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1166
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1167
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1168
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1169
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1170
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1171
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1172
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1173
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1174
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1175
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1176
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1177
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1178
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1179
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1180
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1181
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1182
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1183
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1184
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1185
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1186
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1187
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1188
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1189
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1190
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1191
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1192
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1193
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1194
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1195
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1196
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1197
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1198
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1199
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1200
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1201
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1202
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1203
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1204
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1205
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1206
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1207
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1208
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1209
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1210
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1211
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1212
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1213
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1214
|
+
<span class="cline-any cline-yes">2x</span>
|
|
1215
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1216
|
+
<span class="cline-any cline-yes">2x</span>
|
|
1217
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1218
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1219
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1220
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1221
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1222
|
+
<span class="cline-any cline-yes">2x</span>
|
|
1223
|
+
<span class="cline-any cline-yes">3x</span>
|
|
1224
|
+
<span class="cline-any cline-yes">3x</span>
|
|
1225
|
+
<span class="cline-any cline-yes">2x</span>
|
|
1226
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1227
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1228
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1229
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1230
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1231
|
+
<span class="cline-any cline-yes">1x</span>
|
|
1232
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1233
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1234
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1235
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1236
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1237
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1238
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1239
|
+
<span class="cline-any cline-yes">2x</span>
|
|
1240
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1241
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1242
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1243
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1244
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1245
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1246
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1247
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1248
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1249
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1250
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1251
|
+
<span class="cline-any cline-yes">2x</span>
|
|
1252
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1253
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1254
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1255
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1256
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1257
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1258
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1259
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1260
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1261
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1262
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1263
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1264
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1265
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1266
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1267
|
+
<span class="cline-any cline-yes">2x</span>
|
|
1268
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1269
|
+
<span class="cline-any cline-yes">2x</span>
|
|
1270
|
+
<span class="cline-any cline-yes">2x</span>
|
|
1271
|
+
<span class="cline-any cline-yes">2x</span>
|
|
1272
|
+
<span class="cline-any cline-yes">2x</span>
|
|
1273
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1274
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1275
|
+
<span class="cline-any cline-yes">2x</span>
|
|
1276
|
+
<span class="cline-any cline-yes">3x</span>
|
|
1277
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1278
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1279
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1280
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1281
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1282
|
+
<span class="cline-any cline-yes">3x</span>
|
|
1283
|
+
<span class="cline-any cline-yes">3x</span>
|
|
1284
|
+
<span class="cline-any cline-yes">3x</span>
|
|
1285
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1286
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1287
|
+
<span class="cline-any cline-yes">2x</span>
|
|
1288
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1289
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1290
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1291
|
+
<span class="cline-any cline-neutral"> </span>
|
|
1292
|
+
<span class="cline-any cline-neutral"> </span></td><td class="text"><pre class="prettyprint lang-js">/**
|
|
1293
|
+
* @fileoverview User management service orchestrating Keycloak operations.
|
|
1294
|
+
* Provides high-level user management with permission checking and audit logging.
|
|
1295
|
+
*
|
|
1296
|
+
* @module services/user
|
|
1297
|
+
*/
|
|
1298
|
+
|
|
1299
|
+
import {
|
|
1300
|
+
PLUGIN_ID,
|
|
1301
|
+
SERVICES,
|
|
1302
|
+
AUDIT_ACTIONS,
|
|
1303
|
+
ERROR_MESSAGES,
|
|
1304
|
+
PAGINATION,
|
|
1305
|
+
} from '../constants.js';
|
|
1306
|
+
import { createSanitizedError } from '../utils/errors.js';
|
|
1307
|
+
|
|
1308
|
+
/**
|
|
1309
|
+
* @typedef {import('./keycloak-client.js').KeycloakUser} KeycloakUser
|
|
1310
|
+
* @typedef {import('./keycloak-client.js').KeycloakRole} KeycloakRole
|
|
1311
|
+
* @typedef {import('./permission.js').StrapiUser} StrapiUser
|
|
1312
|
+
* @typedef {import('./permission.js').RealmPermissions} RealmPermissions
|
|
1313
|
+
*/
|
|
1314
|
+
|
|
1315
|
+
/**
|
|
1316
|
+
* @typedef {Object} PaginatedUsersResult
|
|
1317
|
+
* @property {KeycloakUser[]} users - Array of users
|
|
1318
|
+
* @property {Object} pagination - Pagination metadata
|
|
1319
|
+
* @property {number} pagination.page - Current page number
|
|
1320
|
+
* @property {number} pagination.pageSize - Items per page
|
|
1321
|
+
* @property {number} pagination.total - Total items
|
|
1322
|
+
* @property {number} pagination.pageCount - Total pages
|
|
1323
|
+
*/
|
|
1324
|
+
|
|
1325
|
+
/**
|
|
1326
|
+
* @typedef {Object} BulkImportResult
|
|
1327
|
+
* @property {Object[]} success - Successfully created users
|
|
1328
|
+
* @property {string} success[].username - Username
|
|
1329
|
+
* @property {string} success[].email - Email
|
|
1330
|
+
* @property {string} success[].userId - Created user ID
|
|
1331
|
+
* @property {Object[]} failed - Failed user creations
|
|
1332
|
+
* @property {string} failed[].username - Username
|
|
1333
|
+
* @property {string} failed[].email - Email
|
|
1334
|
+
* @property {string} failed[].error - Error message
|
|
1335
|
+
*/
|
|
1336
|
+
|
|
1337
|
+
/**
|
|
1338
|
+
* Creates the user management service.
|
|
1339
|
+
*
|
|
1340
|
+
* @param {Object} params - Service parameters
|
|
1341
|
+
* @param {Object} params.strapi - Strapi instance
|
|
1342
|
+
* @returns {Object} User service methods
|
|
1343
|
+
*/
|
|
1344
|
+
const userService = ({ strapi }) => ({
|
|
1345
|
+
/**
|
|
1346
|
+
* Gets the realm service instance.
|
|
1347
|
+
* @returns {Object} Realm service
|
|
1348
|
+
* @private
|
|
1349
|
+
*/
|
|
1350
|
+
get realmService() {
|
|
1351
|
+
return strapi.plugin(PLUGIN_ID).service(SERVICES.REALM);
|
|
1352
|
+
},
|
|
1353
|
+
|
|
1354
|
+
/**
|
|
1355
|
+
* Gets the Keycloak client service instance.
|
|
1356
|
+
* @returns {Object} Keycloak client service
|
|
1357
|
+
* @private
|
|
1358
|
+
*/
|
|
1359
|
+
get keycloakClient() {
|
|
1360
|
+
return strapi.plugin(PLUGIN_ID).service(SERVICES.KEYCLOAK_CLIENT);
|
|
1361
|
+
},
|
|
1362
|
+
|
|
1363
|
+
/**
|
|
1364
|
+
* Gets the permission service instance.
|
|
1365
|
+
* @returns {Object} Permission service
|
|
1366
|
+
* @private
|
|
1367
|
+
*/
|
|
1368
|
+
get permissionService() {
|
|
1369
|
+
return strapi.plugin(PLUGIN_ID).service(SERVICES.PERMISSION);
|
|
1370
|
+
},
|
|
1371
|
+
|
|
1372
|
+
/**
|
|
1373
|
+
* Gets the audit log service instance.
|
|
1374
|
+
* @returns {Object} Audit log service
|
|
1375
|
+
* @private
|
|
1376
|
+
*/
|
|
1377
|
+
get auditLogService() {
|
|
1378
|
+
return strapi.plugin(PLUGIN_ID).service(SERVICES.AUDIT_LOG);
|
|
1379
|
+
},
|
|
1380
|
+
|
|
1381
|
+
/**
|
|
1382
|
+
* Validates user permission and returns realm config with credentials.
|
|
1383
|
+
* This is the primary permission gate for all user operations.
|
|
1384
|
+
*
|
|
1385
|
+
* @param {string} realmId - Realm document ID
|
|
1386
|
+
* @param {StrapiUser} user - Strapi user requesting access
|
|
1387
|
+
* @param {keyof RealmPermissions} permission - Required permission
|
|
1388
|
+
* @returns {Promise<Object>} Realm config with clientSecret for API calls
|
|
1389
|
+
* @throws {Error} If realm disabled or user lacks permission
|
|
1390
|
+
* @private
|
|
1391
|
+
*
|
|
1392
|
+
* @example
|
|
1393
|
+
* const realm = await this.getRealmWithPermission(realmId, user, 'canCreate');
|
|
1394
|
+
* // Now safe to call Keycloak APIs
|
|
1395
|
+
*/
|
|
1396
|
+
async getRealmWithPermission(realmId, user, permission) {
|
|
1397
|
+
// First check if realm exists and is enabled
|
|
1398
|
+
const realmBasic = await this.realmService.findOne(realmId);
|
|
1399
|
+
|
|
1400
|
+
if (!realmBasic.enabled) {
|
|
1401
|
+
throw createSanitizedError('Realm disabled', ERROR_MESSAGES.REALM_DISABLED);
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
// Check user permission
|
|
1405
|
+
const hasPermission = await this.permissionService.canAccessRealm(user, realmId, permission);
|
|
1406
|
+
|
|
1407
|
+
if (!hasPermission) {
|
|
1408
|
+
throw createSanitizedError(
|
|
1409
|
+
`User ${user.id} lacks ${permission} for realm ${realmId}`,
|
|
1410
|
+
ERROR_MESSAGES.REALM_ACCESS_DENIED
|
|
1411
|
+
);
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
// Get realm with clientSecret for Keycloak API calls
|
|
1415
|
+
return this.realmService.findOneWithSecret(realmId);
|
|
1416
|
+
},
|
|
1417
|
+
|
|
1418
|
+
/**
|
|
1419
|
+
* Lists users from a Keycloak realm with pagination.
|
|
1420
|
+
*
|
|
1421
|
+
* @param {string} realmId - Realm document ID
|
|
1422
|
+
* @param {Object} [options={}] - Query options
|
|
1423
|
+
* @param {string} [options.search=''] - Search query
|
|
1424
|
+
* @param {number} [options.page=1] - Page number (1-indexed)
|
|
1425
|
+
* @param {number} [options.pageSize=25] - Items per page
|
|
1426
|
+
* @param {StrapiUser} strapiUser - User making the request
|
|
1427
|
+
* @returns {Promise<PaginatedUsersResult>} Paginated users
|
|
1428
|
+
*
|
|
1429
|
+
* @example
|
|
1430
|
+
* const { users, pagination } = await userService.listUsers(
|
|
1431
|
+
* realmId,
|
|
1432
|
+
* { search: 'john', page: 1, pageSize: 10 },
|
|
1433
|
+
* ctx.state.user
|
|
1434
|
+
* );
|
|
1435
|
+
*/
|
|
1436
|
+
async listUsers(realmId, { search = '', page = 1, pageSize = PAGINATION.PAGE_SIZE } = <span class="branch-0 cbranch-no" title="branch not covered" >{},</span> strapiUser) {
|
|
1437
|
+
const realm = await this.getRealmWithPermission(realmId, strapiUser, 'canRead');
|
|
1438
|
+
|
|
1439
|
+
const first = (page - 1) * pageSize;
|
|
1440
|
+
const [users, total] = await Promise.all([
|
|
1441
|
+
this.keycloakClient.getUsers(realm, { search, first, max: pageSize }),
|
|
1442
|
+
this.keycloakClient.countUsers(realm, { search }),
|
|
1443
|
+
]);
|
|
1444
|
+
|
|
1445
|
+
return {
|
|
1446
|
+
users,
|
|
1447
|
+
pagination: {
|
|
1448
|
+
page,
|
|
1449
|
+
pageSize,
|
|
1450
|
+
total,
|
|
1451
|
+
pageCount: Math.ceil(total / pageSize),
|
|
1452
|
+
},
|
|
1453
|
+
};
|
|
1454
|
+
},
|
|
1455
|
+
|
|
1456
|
+
/**
|
|
1457
|
+
* Retrieves a single user by Keycloak ID.
|
|
1458
|
+
*
|
|
1459
|
+
* @param {string} realmId - Realm document ID
|
|
1460
|
+
* @param {string} keycloakUserId - Keycloak user ID
|
|
1461
|
+
* @param {StrapiUser} strapiUser - User making the request
|
|
1462
|
+
* @returns {Promise<KeycloakUser>} User details
|
|
1463
|
+
*
|
|
1464
|
+
* @example
|
|
1465
|
+
* const user = await userService.getUser(realmId, 'kc-user-123', ctx.state.user);
|
|
1466
|
+
*/
|
|
1467
|
+
async getUser(realmId, keycloakUserId, strapiUser) {
|
|
1468
|
+
const realm = await this.getRealmWithPermission(realmId, strapiUser, 'canRead');
|
|
1469
|
+
return this.keycloakClient.getUserById(realm, keycloakUserId);
|
|
1470
|
+
},
|
|
1471
|
+
|
|
1472
|
+
/**
|
|
1473
|
+
* Creates a new user in Keycloak.
|
|
1474
|
+
*
|
|
1475
|
+
* @param {string} realmId - Realm document ID
|
|
1476
|
+
* @param {Object} userData - User data
|
|
1477
|
+
* @param {string} userData.username - Required username
|
|
1478
|
+
* @param {string} [userData.email] - Email address
|
|
1479
|
+
* @param {string} [userData.firstName] - First name
|
|
1480
|
+
* @param {string} [userData.lastName] - Last name
|
|
1481
|
+
* @param {boolean} [userData.enabled=true] - Account enabled
|
|
1482
|
+
* @param {StrapiUser} strapiUser - User making the request
|
|
1483
|
+
* @returns {Promise<KeycloakUser>} Created user
|
|
1484
|
+
*
|
|
1485
|
+
* @example
|
|
1486
|
+
* const user = await userService.createUser(
|
|
1487
|
+
* realmId,
|
|
1488
|
+
* { username: 'newuser', email: 'new@example.com' },
|
|
1489
|
+
* ctx.state.user
|
|
1490
|
+
* );
|
|
1491
|
+
*/
|
|
1492
|
+
async createUser(realmId, userData, strapiUser) {
|
|
1493
|
+
const realm = await this.getRealmWithPermission(realmId, strapiUser, 'canCreate');
|
|
1494
|
+
|
|
1495
|
+
const result = await this.keycloakClient.createUser(realm, userData);
|
|
1496
|
+
|
|
1497
|
+
// Log the action
|
|
1498
|
+
await this.auditLogService.log({
|
|
1499
|
+
realmName: realm.name,
|
|
1500
|
+
realmDisplayName: realm.displayName,
|
|
1501
|
+
action: AUDIT_ACTIONS.CREATE_USER,
|
|
1502
|
+
keycloakUserId: result.userId,
|
|
1503
|
+
keycloakUsername: userData.username,
|
|
1504
|
+
details: {
|
|
1505
|
+
email: userData.email,
|
|
1506
|
+
firstName: userData.firstName,
|
|
1507
|
+
lastName: userData.lastName
|
|
1508
|
+
},
|
|
1509
|
+
user: strapiUser,
|
|
1510
|
+
});
|
|
1511
|
+
|
|
1512
|
+
// Fetch and return the created user if we have the ID
|
|
1513
|
+
<span class="missing-if-branch" title="else path not taken" >E</span>if (result.userId) {
|
|
1514
|
+
return this.keycloakClient.getUserById(realm, result.userId);
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
<span class="cstat-no" title="statement not covered" > return result;</span>
|
|
1518
|
+
},
|
|
1519
|
+
|
|
1520
|
+
/**
|
|
1521
|
+
* Updates an existing user's attributes.
|
|
1522
|
+
*
|
|
1523
|
+
* @param {string} realmId - Realm document ID
|
|
1524
|
+
* @param {string} keycloakUserId - Keycloak user ID
|
|
1525
|
+
* @param {Object} userData - Fields to update
|
|
1526
|
+
* @param {StrapiUser} strapiUser - User making the request
|
|
1527
|
+
* @returns {Promise<KeycloakUser>} Updated user
|
|
1528
|
+
*
|
|
1529
|
+
* @example
|
|
1530
|
+
* const user = await userService.updateUser(
|
|
1531
|
+
* realmId,
|
|
1532
|
+
* 'kc-user-123',
|
|
1533
|
+
* { firstName: 'Updated', lastName: 'Name' },
|
|
1534
|
+
* ctx.state.user
|
|
1535
|
+
* );
|
|
1536
|
+
*/
|
|
1537
|
+
async updateUser(realmId, keycloakUserId, userData, strapiUser) {
|
|
1538
|
+
const realm = await this.getRealmWithPermission(realmId, strapiUser, 'canUpdate');
|
|
1539
|
+
|
|
1540
|
+
// Get current user data for audit
|
|
1541
|
+
const currentUser = await this.keycloakClient.getUserById(realm, keycloakUserId);
|
|
1542
|
+
|
|
1543
|
+
await this.keycloakClient.updateUser(realm, keycloakUserId, userData);
|
|
1544
|
+
|
|
1545
|
+
await this.auditLogService.log({
|
|
1546
|
+
realmName: realm.name,
|
|
1547
|
+
realmDisplayName: realm.displayName,
|
|
1548
|
+
action: AUDIT_ACTIONS.UPDATE_USER,
|
|
1549
|
+
keycloakUserId,
|
|
1550
|
+
keycloakUsername: currentUser.username,
|
|
1551
|
+
details: { changes: userData },
|
|
1552
|
+
user: strapiUser,
|
|
1553
|
+
});
|
|
1554
|
+
|
|
1555
|
+
return this.keycloakClient.getUserById(realm, keycloakUserId);
|
|
1556
|
+
},
|
|
1557
|
+
|
|
1558
|
+
/**
|
|
1559
|
+
* Permanently deletes a user from Keycloak.
|
|
1560
|
+
*
|
|
1561
|
+
* @param {string} realmId - Realm document ID
|
|
1562
|
+
* @param {string} keycloakUserId - Keycloak user ID
|
|
1563
|
+
* @param {StrapiUser} strapiUser - User making the request
|
|
1564
|
+
* @returns {Promise<{success: boolean}>} Success indicator
|
|
1565
|
+
*
|
|
1566
|
+
* @example
|
|
1567
|
+
* await userService.deleteUser(realmId, 'kc-user-123', ctx.state.user);
|
|
1568
|
+
*/
|
|
1569
|
+
async deleteUser(realmId, keycloakUserId, strapiUser) {
|
|
1570
|
+
const realm = await this.getRealmWithPermission(realmId, strapiUser, 'canDelete');
|
|
1571
|
+
|
|
1572
|
+
// Get user data for audit before deletion
|
|
1573
|
+
const user = await this.keycloakClient.getUserById(realm, keycloakUserId);
|
|
1574
|
+
|
|
1575
|
+
await this.keycloakClient.deleteUser(realm, keycloakUserId);
|
|
1576
|
+
|
|
1577
|
+
await this.auditLogService.log({
|
|
1578
|
+
realmName: realm.name,
|
|
1579
|
+
realmDisplayName: realm.displayName,
|
|
1580
|
+
action: AUDIT_ACTIONS.DELETE_USER,
|
|
1581
|
+
keycloakUserId,
|
|
1582
|
+
keycloakUsername: user.username,
|
|
1583
|
+
details: { email: user.email },
|
|
1584
|
+
user: strapiUser,
|
|
1585
|
+
});
|
|
1586
|
+
|
|
1587
|
+
return { success: true };
|
|
1588
|
+
},
|
|
1589
|
+
|
|
1590
|
+
/**
|
|
1591
|
+
* Resets a user's password.
|
|
1592
|
+
* Requires canResetPassword permission (separate from canUpdate for compliance).
|
|
1593
|
+
*
|
|
1594
|
+
* @param {string} realmId - Realm document ID
|
|
1595
|
+
* @param {string} keycloakUserId - Keycloak user ID
|
|
1596
|
+
* @param {string} password - New password
|
|
1597
|
+
* @param {boolean} temporary - Whether password must be changed on next login
|
|
1598
|
+
* @param {StrapiUser} strapiUser - User making the request
|
|
1599
|
+
* @returns {Promise<{success: boolean}>} Success indicator
|
|
1600
|
+
*
|
|
1601
|
+
* @example
|
|
1602
|
+
* // Set temporary password
|
|
1603
|
+
* await userService.resetPassword(realmId, userId, 'TempPass123!', true, user);
|
|
1604
|
+
*/
|
|
1605
|
+
async resetPassword(realmId, keycloakUserId, password, temporary, strapiUser) {
|
|
1606
|
+
const realm = await this.getRealmWithPermission(realmId, strapiUser, 'canResetPassword');
|
|
1607
|
+
|
|
1608
|
+
const user = await this.keycloakClient.getUserById(realm, keycloakUserId);
|
|
1609
|
+
await this.keycloakClient.resetPassword(realm, keycloakUserId, password, temporary);
|
|
1610
|
+
|
|
1611
|
+
await this.auditLogService.log({
|
|
1612
|
+
realmName: realm.name,
|
|
1613
|
+
realmDisplayName: realm.displayName,
|
|
1614
|
+
action: AUDIT_ACTIONS.RESET_PASSWORD,
|
|
1615
|
+
keycloakUserId,
|
|
1616
|
+
keycloakUsername: user.username,
|
|
1617
|
+
details: { temporary },
|
|
1618
|
+
user: strapiUser,
|
|
1619
|
+
});
|
|
1620
|
+
|
|
1621
|
+
return { success: true };
|
|
1622
|
+
},
|
|
1623
|
+
|
|
1624
|
+
/**
|
|
1625
|
+
* Enables a user account.
|
|
1626
|
+
*
|
|
1627
|
+
* @param {string} realmId - Realm document ID
|
|
1628
|
+
* @param {string} keycloakUserId - Keycloak user ID
|
|
1629
|
+
* @param {StrapiUser} strapiUser - User making the request
|
|
1630
|
+
* @returns {Promise<{success: boolean}>} Success indicator
|
|
1631
|
+
*/
|
|
1632
|
+
async enableUser(realmId, keycloakUserId, strapiUser) {
|
|
1633
|
+
const realm = await this.getRealmWithPermission(realmId, strapiUser, 'canUpdate');
|
|
1634
|
+
|
|
1635
|
+
const user = await this.keycloakClient.getUserById(realm, keycloakUserId);
|
|
1636
|
+
await this.keycloakClient.enableUser(realm, keycloakUserId);
|
|
1637
|
+
|
|
1638
|
+
await this.auditLogService.log({
|
|
1639
|
+
realmName: realm.name,
|
|
1640
|
+
realmDisplayName: realm.displayName,
|
|
1641
|
+
action: AUDIT_ACTIONS.ENABLE_USER,
|
|
1642
|
+
keycloakUserId,
|
|
1643
|
+
keycloakUsername: user.username,
|
|
1644
|
+
user: strapiUser,
|
|
1645
|
+
});
|
|
1646
|
+
|
|
1647
|
+
return { success: true };
|
|
1648
|
+
},
|
|
1649
|
+
|
|
1650
|
+
/**
|
|
1651
|
+
* Disables a user account.
|
|
1652
|
+
*
|
|
1653
|
+
* @param {string} realmId - Realm document ID
|
|
1654
|
+
* @param {string} keycloakUserId - Keycloak user ID
|
|
1655
|
+
* @param {StrapiUser} strapiUser - User making the request
|
|
1656
|
+
* @returns {Promise<{success: boolean}>} Success indicator
|
|
1657
|
+
*/
|
|
1658
|
+
async disableUser(realmId, keycloakUserId, strapiUser) {
|
|
1659
|
+
const realm = await this.getRealmWithPermission(realmId, strapiUser, 'canUpdate');
|
|
1660
|
+
|
|
1661
|
+
const user = await this.keycloakClient.getUserById(realm, keycloakUserId);
|
|
1662
|
+
await this.keycloakClient.disableUser(realm, keycloakUserId);
|
|
1663
|
+
|
|
1664
|
+
await this.auditLogService.log({
|
|
1665
|
+
realmName: realm.name,
|
|
1666
|
+
realmDisplayName: realm.displayName,
|
|
1667
|
+
action: AUDIT_ACTIONS.DISABLE_USER,
|
|
1668
|
+
keycloakUserId,
|
|
1669
|
+
keycloakUsername: user.username,
|
|
1670
|
+
user: strapiUser,
|
|
1671
|
+
});
|
|
1672
|
+
|
|
1673
|
+
return { success: true };
|
|
1674
|
+
},
|
|
1675
|
+
|
|
1676
|
+
/**
|
|
1677
|
+
* Sends an email verification link to the user.
|
|
1678
|
+
*
|
|
1679
|
+
* @param {string} realmId - Realm document ID
|
|
1680
|
+
* @param {string} keycloakUserId - Keycloak user ID
|
|
1681
|
+
* @param {StrapiUser} strapiUser - User making the request
|
|
1682
|
+
* @returns {Promise<{success: boolean}>} Success indicator
|
|
1683
|
+
*/
|
|
1684
|
+
async sendVerificationEmail(realmId, keycloakUserId, strapiUser) {
|
|
1685
|
+
const realm = await this.getRealmWithPermission(realmId, strapiUser, 'canUpdate');
|
|
1686
|
+
|
|
1687
|
+
const user = await this.keycloakClient.getUserById(realm, keycloakUserId);
|
|
1688
|
+
await this.keycloakClient.sendVerificationEmail(realm, keycloakUserId);
|
|
1689
|
+
|
|
1690
|
+
await this.auditLogService.log({
|
|
1691
|
+
realmName: realm.name,
|
|
1692
|
+
realmDisplayName: realm.displayName,
|
|
1693
|
+
action: AUDIT_ACTIONS.SEND_VERIFY_EMAIL,
|
|
1694
|
+
keycloakUserId,
|
|
1695
|
+
keycloakUsername: user.username,
|
|
1696
|
+
user: strapiUser,
|
|
1697
|
+
});
|
|
1698
|
+
|
|
1699
|
+
return { success: true };
|
|
1700
|
+
},
|
|
1701
|
+
|
|
1702
|
+
/**
|
|
1703
|
+
* Sends a password reset email to the user.
|
|
1704
|
+
* Requires canResetPassword permission.
|
|
1705
|
+
*
|
|
1706
|
+
* @param {string} realmId - Realm document ID
|
|
1707
|
+
* @param {string} keycloakUserId - Keycloak user ID
|
|
1708
|
+
* @param {StrapiUser} strapiUser - User making the request
|
|
1709
|
+
* @returns {Promise<{success: boolean}>} Success indicator
|
|
1710
|
+
*/
|
|
1711
|
+
async sendResetPasswordEmail(realmId, keycloakUserId, strapiUser) {
|
|
1712
|
+
const realm = await this.getRealmWithPermission(realmId, strapiUser, 'canResetPassword');
|
|
1713
|
+
|
|
1714
|
+
const user = await this.keycloakClient.getUserById(realm, keycloakUserId);
|
|
1715
|
+
await this.keycloakClient.sendResetPasswordEmail(realm, keycloakUserId);
|
|
1716
|
+
|
|
1717
|
+
await this.auditLogService.log({
|
|
1718
|
+
realmName: realm.name,
|
|
1719
|
+
realmDisplayName: realm.displayName,
|
|
1720
|
+
action: AUDIT_ACTIONS.SEND_RESET_PASSWORD_EMAIL,
|
|
1721
|
+
keycloakUserId,
|
|
1722
|
+
keycloakUsername: user.username,
|
|
1723
|
+
user: strapiUser,
|
|
1724
|
+
});
|
|
1725
|
+
|
|
1726
|
+
return { success: true };
|
|
1727
|
+
},
|
|
1728
|
+
|
|
1729
|
+
/**
|
|
1730
|
+
* Retrieves all realm roles.
|
|
1731
|
+
*
|
|
1732
|
+
* @param {string} realmId - Realm document ID
|
|
1733
|
+
* @param {StrapiUser} strapiUser - User making the request
|
|
1734
|
+
* @returns {Promise<KeycloakRole[]>} Array of realm roles
|
|
1735
|
+
*/
|
|
1736
|
+
async getRoles(realmId, strapiUser) {
|
|
1737
|
+
const realm = await this.getRealmWithPermission(realmId, strapiUser, 'canRead');
|
|
1738
|
+
return this.keycloakClient.getRealmRoles(realm);
|
|
1739
|
+
},
|
|
1740
|
+
|
|
1741
|
+
/**
|
|
1742
|
+
* Gets roles assigned to a user.
|
|
1743
|
+
*
|
|
1744
|
+
* @param {string} realmId - Realm document ID
|
|
1745
|
+
* @param {string} keycloakUserId - Keycloak user ID
|
|
1746
|
+
* @param {StrapiUser} strapiUser - User making the request
|
|
1747
|
+
* @returns {Promise<KeycloakRole[]>} User's assigned roles
|
|
1748
|
+
*/
|
|
1749
|
+
async getUserRoles(realmId, keycloakUserId, strapiUser) {
|
|
1750
|
+
const realm = await this.getRealmWithPermission(realmId, strapiUser, 'canRead');
|
|
1751
|
+
return this.keycloakClient.getUserRoles(realm, keycloakUserId);
|
|
1752
|
+
},
|
|
1753
|
+
|
|
1754
|
+
/**
|
|
1755
|
+
* Assigns roles to a user.
|
|
1756
|
+
*
|
|
1757
|
+
* @param {string} realmId - Realm document ID
|
|
1758
|
+
* @param {string} keycloakUserId - Keycloak user ID
|
|
1759
|
+
* @param {KeycloakRole[]} roles - Roles to assign
|
|
1760
|
+
* @param {StrapiUser} strapiUser - User making the request
|
|
1761
|
+
* @returns {Promise<{success: boolean}>} Success indicator
|
|
1762
|
+
*/
|
|
1763
|
+
async assignRoles(realmId, keycloakUserId, roles, strapiUser) {
|
|
1764
|
+
const realm = await this.getRealmWithPermission(realmId, strapiUser, 'canManageRoles');
|
|
1765
|
+
|
|
1766
|
+
const user = await this.keycloakClient.getUserById(realm, keycloakUserId);
|
|
1767
|
+
await this.keycloakClient.assignRoles(realm, keycloakUserId, roles);
|
|
1768
|
+
|
|
1769
|
+
await this.auditLogService.log({
|
|
1770
|
+
realmName: realm.name,
|
|
1771
|
+
realmDisplayName: realm.displayName,
|
|
1772
|
+
action: AUDIT_ACTIONS.ASSIGN_ROLE,
|
|
1773
|
+
keycloakUserId,
|
|
1774
|
+
keycloakUsername: user.username,
|
|
1775
|
+
details: { roles: roles.map((r) => r.name) },
|
|
1776
|
+
user: strapiUser,
|
|
1777
|
+
});
|
|
1778
|
+
|
|
1779
|
+
return { success: true };
|
|
1780
|
+
},
|
|
1781
|
+
|
|
1782
|
+
/**
|
|
1783
|
+
* Removes roles from a user.
|
|
1784
|
+
*
|
|
1785
|
+
* @param {string} realmId - Realm document ID
|
|
1786
|
+
* @param {string} keycloakUserId - Keycloak user ID
|
|
1787
|
+
* @param {KeycloakRole[]} roles - Roles to remove
|
|
1788
|
+
* @param {StrapiUser} strapiUser - User making the request
|
|
1789
|
+
* @returns {Promise<{success: boolean}>} Success indicator
|
|
1790
|
+
*/
|
|
1791
|
+
async removeRoles(realmId, keycloakUserId, roles, strapiUser) {
|
|
1792
|
+
const realm = await this.getRealmWithPermission(realmId, strapiUser, 'canManageRoles');
|
|
1793
|
+
|
|
1794
|
+
const user = await this.keycloakClient.getUserById(realm, keycloakUserId);
|
|
1795
|
+
await this.keycloakClient.removeRoles(realm, keycloakUserId, roles);
|
|
1796
|
+
|
|
1797
|
+
await this.auditLogService.log({
|
|
1798
|
+
realmName: realm.name,
|
|
1799
|
+
realmDisplayName: realm.displayName,
|
|
1800
|
+
action: AUDIT_ACTIONS.REMOVE_ROLE,
|
|
1801
|
+
keycloakUserId,
|
|
1802
|
+
keycloakUsername: user.username,
|
|
1803
|
+
details: { roles: roles.map((r) => r.name) },
|
|
1804
|
+
user: strapiUser,
|
|
1805
|
+
});
|
|
1806
|
+
|
|
1807
|
+
return { success: true };
|
|
1808
|
+
},
|
|
1809
|
+
|
|
1810
|
+
/**
|
|
1811
|
+
* Bulk imports users from an array of user data.
|
|
1812
|
+
* Processes users sequentially to handle errors gracefully.
|
|
1813
|
+
*
|
|
1814
|
+
* @param {string} realmId - Realm document ID
|
|
1815
|
+
* @param {Object[]} users - Array of user data objects
|
|
1816
|
+
* @param {StrapiUser} strapiUser - User making the request
|
|
1817
|
+
* @returns {Promise<BulkImportResult>} Import results with success/failed arrays
|
|
1818
|
+
*
|
|
1819
|
+
* @example
|
|
1820
|
+
* const result = await userService.bulkImport(realmId, [
|
|
1821
|
+
* { username: 'user1', email: 'user1@example.com' },
|
|
1822
|
+
* { username: 'user2', email: 'user2@example.com' }
|
|
1823
|
+
* ], ctx.state.user);
|
|
1824
|
+
* console.log(`Created ${result.success.length}, Failed ${result.failed.length}`);
|
|
1825
|
+
*/
|
|
1826
|
+
async bulkImport(realmId, users, strapiUser) {
|
|
1827
|
+
const realm = await this.getRealmWithPermission(realmId, strapiUser, 'canCreate');
|
|
1828
|
+
|
|
1829
|
+
const results = {
|
|
1830
|
+
success: [],
|
|
1831
|
+
failed: [],
|
|
1832
|
+
};
|
|
1833
|
+
|
|
1834
|
+
// Process users sequentially for better error handling
|
|
1835
|
+
for (const userData of users) {
|
|
1836
|
+
try {
|
|
1837
|
+
const result = await this.keycloakClient.createUser(realm, userData);
|
|
1838
|
+
results.success.push({
|
|
1839
|
+
username: userData.username,
|
|
1840
|
+
email: userData.email,
|
|
1841
|
+
userId: result.userId,
|
|
1842
|
+
});
|
|
1843
|
+
} catch (err) {
|
|
1844
|
+
results.failed.push({
|
|
1845
|
+
username: userData.username,
|
|
1846
|
+
email: userData.email,
|
|
1847
|
+
error: err.sanitizedMessage || <span class="branch-1 cbranch-no" title="branch not covered" >err.message,</span>
|
|
1848
|
+
});
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
|
|
1852
|
+
await this.auditLogService.log({
|
|
1853
|
+
realmName: realm.name,
|
|
1854
|
+
realmDisplayName: realm.displayName,
|
|
1855
|
+
action: AUDIT_ACTIONS.BULK_IMPORT,
|
|
1856
|
+
details: {
|
|
1857
|
+
totalAttempted: users.length,
|
|
1858
|
+
successCount: results.success.length,
|
|
1859
|
+
failedCount: results.failed.length,
|
|
1860
|
+
},
|
|
1861
|
+
user: strapiUser,
|
|
1862
|
+
});
|
|
1863
|
+
|
|
1864
|
+
return results;
|
|
1865
|
+
},
|
|
1866
|
+
|
|
1867
|
+
/**
|
|
1868
|
+
* Exports all users from a realm.
|
|
1869
|
+
* Fetches users in batches for performance.
|
|
1870
|
+
*
|
|
1871
|
+
* @param {string} realmId - Realm document ID
|
|
1872
|
+
* @param {StrapiUser} strapiUser - User making the request
|
|
1873
|
+
* @returns {Promise<KeycloakUser[]>} All users in the realm
|
|
1874
|
+
*
|
|
1875
|
+
* @example
|
|
1876
|
+
* const users = await userService.exportUsers(realmId, ctx.state.user);
|
|
1877
|
+
* // Convert to CSV or JSON for download
|
|
1878
|
+
*/
|
|
1879
|
+
async exportUsers(realmId, strapiUser) {
|
|
1880
|
+
const realm = await this.getRealmWithPermission(realmId, strapiUser, 'canRead');
|
|
1881
|
+
|
|
1882
|
+
const allUsers = [];
|
|
1883
|
+
let first = 0;
|
|
1884
|
+
const max = PAGINATION.EXPORT_BATCH_SIZE;
|
|
1885
|
+
let hasMore = true;
|
|
1886
|
+
|
|
1887
|
+
// Fetch users in batches
|
|
1888
|
+
while (hasMore) {
|
|
1889
|
+
const users = await this.keycloakClient.getUsers(realm, {
|
|
1890
|
+
first,
|
|
1891
|
+
max,
|
|
1892
|
+
briefRepresentation: false,
|
|
1893
|
+
});
|
|
1894
|
+
|
|
1895
|
+
allUsers.push(...users);
|
|
1896
|
+
first += max;
|
|
1897
|
+
hasMore = users.length === max;
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1900
|
+
return allUsers;
|
|
1901
|
+
},
|
|
1902
|
+
});
|
|
1903
|
+
|
|
1904
|
+
export default userService;
|
|
1905
|
+
</pre></td></tr></table></pre>
|
|
1906
|
+
|
|
1907
|
+
<div class='push'></div><!-- for sticky footer -->
|
|
1908
|
+
</div><!-- /wrapper -->
|
|
1909
|
+
<div class='footer quiet pad2 space-top1 center small'>
|
|
1910
|
+
Code coverage generated by
|
|
1911
|
+
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
1912
|
+
at 2026-02-05T14:19:59.409Z
|
|
1913
|
+
</div>
|
|
1914
|
+
<script src="../../prettify.js"></script>
|
|
1915
|
+
<script>
|
|
1916
|
+
window.onload = function () {
|
|
1917
|
+
prettyPrint();
|
|
1918
|
+
};
|
|
1919
|
+
</script>
|
|
1920
|
+
<script src="../../sorter.js"></script>
|
|
1921
|
+
<script src="../../block-navigation.js"></script>
|
|
1922
|
+
</body>
|
|
1923
|
+
</html>
|
|
1924
|
+
|