@switchbot/homebridge-switchbot 4.3.2-beta.8 → 4.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (222) hide show
  1. package/.github/copilot-instructions.md +328 -0
  2. package/.github/scripts/npm-version-script-esm-auto.js +207 -0
  3. package/.github/workflows/beta-release.yml +8 -12
  4. package/.github/workflows/release.yml +54 -22
  5. package/CHANGELOG.md +1 -1
  6. package/README.md +13 -10
  7. package/config.schema.json +2 -2
  8. package/coverage/base.css +224 -0
  9. package/coverage/block-navigation.js +87 -0
  10. package/coverage/clover.xml +15847 -0
  11. package/coverage/coverage-final.json +42 -0
  12. package/coverage/docs/assets/dmt/dmt-component-data.js.html +85 -0
  13. package/coverage/docs/assets/dmt/dmt-components.js.html +286 -0
  14. package/coverage/docs/assets/dmt/index.html +131 -0
  15. package/coverage/docs/assets/hierarchy.js.html +85 -0
  16. package/coverage/docs/assets/icons.js.html +136 -0
  17. package/coverage/docs/assets/index.html +146 -0
  18. package/coverage/docs/assets/main.js.html +265 -0
  19. package/coverage/favicon.png +0 -0
  20. package/coverage/index.html +191 -0
  21. package/coverage/prettify.css +1 -0
  22. package/coverage/prettify.js +2 -0
  23. package/coverage/sort-arrow-sprite.png +0 -0
  24. package/coverage/sorter.js +196 -0
  25. package/coverage/src/device/blindtilt.ts.html +3238 -0
  26. package/coverage/src/device/bot.ts.html +2803 -0
  27. package/coverage/src/device/ceilinglight.ts.html +2338 -0
  28. package/coverage/src/device/colorbulb.ts.html +2824 -0
  29. package/coverage/src/device/contact.ts.html +1465 -0
  30. package/coverage/src/device/curtain.ts.html +2869 -0
  31. package/coverage/src/device/device.ts.html +2500 -0
  32. package/coverage/src/device/fan.ts.html +2242 -0
  33. package/coverage/src/device/hub.ts.html +1408 -0
  34. package/coverage/src/device/humidifier.ts.html +2116 -0
  35. package/coverage/src/device/index.html +416 -0
  36. package/coverage/src/device/iosensor.ts.html +1375 -0
  37. package/coverage/src/device/lightstrip.ts.html +2617 -0
  38. package/coverage/src/device/lock.ts.html +1963 -0
  39. package/coverage/src/device/meter.ts.html +1372 -0
  40. package/coverage/src/device/meterplus.ts.html +1384 -0
  41. package/coverage/src/device/meterpro.ts.html +1618 -0
  42. package/coverage/src/device/motion.ts.html +1264 -0
  43. package/coverage/src/device/plug.ts.html +1372 -0
  44. package/coverage/src/device/relayswitch.ts.html +2284 -0
  45. package/coverage/src/device/robotvacuumcleaner.ts.html +1810 -0
  46. package/coverage/src/device/waterdetector.ts.html +1294 -0
  47. package/coverage/src/homebridge-ui/index.html +116 -0
  48. package/coverage/src/homebridge-ui/server.ts.html +229 -0
  49. package/coverage/src/index.html +161 -0
  50. package/coverage/src/index.ts.html +124 -0
  51. package/coverage/src/irdevice/airconditioner.ts.html +1687 -0
  52. package/coverage/src/irdevice/airpurifier.ts.html +844 -0
  53. package/coverage/src/irdevice/camera.ts.html +475 -0
  54. package/coverage/src/irdevice/fan.ts.html +766 -0
  55. package/coverage/src/irdevice/index.html +251 -0
  56. package/coverage/src/irdevice/irdevice.ts.html +1117 -0
  57. package/coverage/src/irdevice/light.ts.html +826 -0
  58. package/coverage/src/irdevice/other.ts.html +2458 -0
  59. package/coverage/src/irdevice/tv.ts.html +1222 -0
  60. package/coverage/src/irdevice/vacuumcleaner.ts.html +466 -0
  61. package/coverage/src/irdevice/waterheater.ts.html +469 -0
  62. package/coverage/src/platform.ts.html +8776 -0
  63. package/coverage/src/settings.ts.html +934 -0
  64. package/coverage/src/utils.ts.html +2092 -0
  65. package/dist/device/blindtilt.d.ts.map +1 -1
  66. package/dist/device/blindtilt.js +12 -4
  67. package/dist/device/blindtilt.js.map +1 -1
  68. package/dist/device/bot.d.ts.map +1 -1
  69. package/dist/device/bot.js +12 -4
  70. package/dist/device/bot.js.map +1 -1
  71. package/dist/device/ceilinglight.d.ts.map +1 -1
  72. package/dist/device/ceilinglight.js +18 -7
  73. package/dist/device/ceilinglight.js.map +1 -1
  74. package/dist/device/colorbulb.d.ts.map +1 -1
  75. package/dist/device/colorbulb.js +18 -7
  76. package/dist/device/colorbulb.js.map +1 -1
  77. package/dist/device/contact.d.ts.map +1 -1
  78. package/dist/device/contact.js +6 -2
  79. package/dist/device/contact.js.map +1 -1
  80. package/dist/device/curtain.d.ts.map +1 -1
  81. package/dist/device/curtain.js +12 -4
  82. package/dist/device/curtain.js.map +1 -1
  83. package/dist/device/device.d.ts +5 -7
  84. package/dist/device/device.d.ts.map +1 -1
  85. package/dist/device/device.js +11 -5
  86. package/dist/device/device.js.map +1 -1
  87. package/dist/device/fan.d.ts.map +1 -1
  88. package/dist/device/fan.js +16 -6
  89. package/dist/device/fan.js.map +1 -1
  90. package/dist/device/hub.d.ts +2 -2
  91. package/dist/device/hub.d.ts.map +1 -1
  92. package/dist/device/hub.js +8 -3
  93. package/dist/device/hub.js.map +1 -1
  94. package/dist/device/humidifier.d.ts.map +1 -1
  95. package/dist/device/humidifier.js +16 -6
  96. package/dist/device/humidifier.js.map +1 -1
  97. package/dist/device/iosensor.d.ts.map +1 -1
  98. package/dist/device/iosensor.js +6 -2
  99. package/dist/device/iosensor.js.map +1 -1
  100. package/dist/device/lightstrip.d.ts.map +1 -1
  101. package/dist/device/lightstrip.js +16 -6
  102. package/dist/device/lightstrip.js.map +1 -1
  103. package/dist/device/lock.d.ts.map +1 -1
  104. package/dist/device/lock.js +12 -4
  105. package/dist/device/lock.js.map +1 -1
  106. package/dist/device/meter.d.ts.map +1 -1
  107. package/dist/device/meter.js +6 -2
  108. package/dist/device/meter.js.map +1 -1
  109. package/dist/device/meterplus.d.ts.map +1 -1
  110. package/dist/device/meterplus.js +6 -2
  111. package/dist/device/meterplus.js.map +1 -1
  112. package/dist/device/meterpro.d.ts.map +1 -1
  113. package/dist/device/meterpro.js +7 -4
  114. package/dist/device/meterpro.js.map +1 -1
  115. package/dist/device/motion.d.ts.map +1 -1
  116. package/dist/device/motion.js +6 -2
  117. package/dist/device/motion.js.map +1 -1
  118. package/dist/device/occupancy.d.ts +42 -0
  119. package/dist/device/occupancy.d.ts.map +1 -0
  120. package/dist/device/occupancy.js +349 -0
  121. package/dist/device/occupancy.js.map +1 -0
  122. package/dist/device/plug.d.ts.map +1 -1
  123. package/dist/device/plug.js +12 -4
  124. package/dist/device/plug.js.map +1 -1
  125. package/dist/device/relayswitch.d.ts.map +1 -1
  126. package/dist/device/relayswitch.js +12 -4
  127. package/dist/device/relayswitch.js.map +1 -1
  128. package/dist/device/robotvacuumcleaner.d.ts.map +1 -1
  129. package/dist/device/robotvacuumcleaner.js +14 -5
  130. package/dist/device/robotvacuumcleaner.js.map +1 -1
  131. package/dist/device/waterdetector.d.ts.map +1 -1
  132. package/dist/device/waterdetector.js +6 -2
  133. package/dist/device/waterdetector.js.map +1 -1
  134. package/dist/homebridge-ui/public/index.html +1 -1
  135. package/dist/irdevice/airconditioner.d.ts.map +1 -1
  136. package/dist/irdevice/airconditioner.js +2 -1
  137. package/dist/irdevice/airconditioner.js.map +1 -1
  138. package/dist/irdevice/airpurifier.d.ts +1 -1
  139. package/dist/irdevice/airpurifier.d.ts.map +1 -1
  140. package/dist/irdevice/airpurifier.js +6 -5
  141. package/dist/irdevice/airpurifier.js.map +1 -1
  142. package/dist/irdevice/camera.d.ts.map +1 -1
  143. package/dist/irdevice/camera.js +2 -1
  144. package/dist/irdevice/camera.js.map +1 -1
  145. package/dist/irdevice/fan.d.ts.map +1 -1
  146. package/dist/irdevice/fan.js +2 -1
  147. package/dist/irdevice/fan.js.map +1 -1
  148. package/dist/irdevice/irdevice.d.ts +2 -6
  149. package/dist/irdevice/irdevice.d.ts.map +1 -1
  150. package/dist/irdevice/irdevice.js.map +1 -1
  151. package/dist/irdevice/light.d.ts.map +1 -1
  152. package/dist/irdevice/light.js +2 -1
  153. package/dist/irdevice/light.js.map +1 -1
  154. package/dist/irdevice/other.d.ts.map +1 -1
  155. package/dist/irdevice/other.js +2 -1
  156. package/dist/irdevice/other.js.map +1 -1
  157. package/dist/irdevice/tv.d.ts.map +1 -1
  158. package/dist/irdevice/tv.js +2 -1
  159. package/dist/irdevice/tv.js.map +1 -1
  160. package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
  161. package/dist/irdevice/vacuumcleaner.js +2 -1
  162. package/dist/irdevice/vacuumcleaner.js.map +1 -1
  163. package/dist/irdevice/waterheater.d.ts.map +1 -1
  164. package/dist/irdevice/waterheater.js +2 -1
  165. package/dist/irdevice/waterheater.js.map +1 -1
  166. package/dist/platform.d.ts +2 -2
  167. package/dist/platform.d.ts.map +1 -1
  168. package/dist/platform.js +77 -78
  169. package/dist/platform.js.map +1 -1
  170. package/dist/settings.d.ts +6 -0
  171. package/dist/settings.d.ts.map +1 -1
  172. package/dist/settings.js +1 -0
  173. package/dist/settings.js.map +1 -1
  174. package/docs/index.html +20 -11
  175. package/docs/variables/default.html +1 -1
  176. package/eslint.config.js +0 -1
  177. package/package.json +7 -8
  178. package/src/device/blindtilt.ts +10 -4
  179. package/src/device/bot.ts +10 -4
  180. package/src/device/ceilinglight.ts +16 -7
  181. package/src/device/colorbulb.ts +16 -7
  182. package/src/device/contact.ts +5 -2
  183. package/src/device/curtain.ts +12 -6
  184. package/src/device/device.ts +14 -8
  185. package/src/device/fan.ts +14 -6
  186. package/src/device/hub.ts +10 -6
  187. package/src/device/humidifier.ts +14 -6
  188. package/src/device/iosensor.ts +5 -2
  189. package/src/device/lightstrip.ts +14 -6
  190. package/src/device/lock.ts +10 -4
  191. package/src/device/meter.ts +6 -3
  192. package/src/device/meterplus.ts +5 -2
  193. package/src/device/meterpro.ts +7 -5
  194. package/src/device/motion.ts +5 -2
  195. package/src/device/occupancy.ts +393 -0
  196. package/src/device/plug.ts +10 -4
  197. package/src/device/relayswitch.ts +10 -4
  198. package/src/device/robotvacuumcleaner.ts +12 -5
  199. package/src/device/waterdetector.ts +5 -2
  200. package/src/homebridge-ui/public/index.html +1 -1
  201. package/src/irdevice/airconditioner.ts +2 -1
  202. package/src/irdevice/airpurifier.ts +6 -5
  203. package/src/irdevice/camera.ts +2 -1
  204. package/src/irdevice/fan.ts +2 -1
  205. package/src/irdevice/irdevice.ts +2 -2
  206. package/src/irdevice/light.ts +2 -1
  207. package/src/irdevice/other.ts +2 -1
  208. package/src/irdevice/tv.ts +2 -1
  209. package/src/irdevice/vacuumcleaner.ts +2 -1
  210. package/src/irdevice/waterheater.ts +2 -1
  211. package/src/platform.ts +80 -88
  212. package/src/settings.ts +7 -0
  213. package/.github/npm-version-script-esm.js +0 -97
  214. package/.github/workflows/build.yml +0 -18
  215. package/.github/workflows/changerelease.yml +0 -11
  216. package/.github/workflows/labeler.yml +0 -16
  217. package/.github/workflows/release-drafter.yml +0 -14
  218. package/dist/device/airpurifier.d.ts +0 -54
  219. package/dist/device/airpurifier.d.ts.map +0 -1
  220. package/dist/device/airpurifier.js +0 -527
  221. package/dist/device/airpurifier.js.map +0 -1
  222. package/src/device/airpurifier.ts +0 -563
@@ -0,0 +1,1408 @@
1
+
2
+ <!doctype html>
3
+ <html lang="en">
4
+
5
+ <head>
6
+ <title>Code coverage report for src/device/hub.ts</title>
7
+ <meta charset="utf-8" />
8
+ <link rel="stylesheet" href="../../prettify.css" />
9
+ <link rel="stylesheet" href="../../base.css" />
10
+ <link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
11
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
12
+ <style type='text/css'>
13
+ .coverage-summary .sorter {
14
+ background-image: url(../../sort-arrow-sprite.png);
15
+ }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <div class='wrapper'>
21
+ <div class='pad1'>
22
+ <h1><a href="../../index.html">All files</a> / <a href="index.html">src/device</a> hub.ts</h1>
23
+ <div class='clearfix'>
24
+
25
+ <div class='fl pad1y space-right2'>
26
+ <span class="strong">1.8% </span>
27
+ <span class="quiet">Statements</span>
28
+ <span class='fraction'>6/332</span>
29
+ </div>
30
+
31
+
32
+ <div class='fl pad1y space-right2'>
33
+ <span class="strong">0% </span>
34
+ <span class="quiet">Branches</span>
35
+ <span class='fraction'>0/1</span>
36
+ </div>
37
+
38
+
39
+ <div class='fl pad1y space-right2'>
40
+ <span class="strong">0% </span>
41
+ <span class="quiet">Functions</span>
42
+ <span class='fraction'>0/1</span>
43
+ </div>
44
+
45
+
46
+ <div class='fl pad1y space-right2'>
47
+ <span class="strong">1.8% </span>
48
+ <span class="quiet">Lines</span>
49
+ <span class='fraction'>6/332</span>
50
+ </div>
51
+
52
+
53
+ </div>
54
+ <p class="quiet">
55
+ Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block.
56
+ </p>
57
+ <template id="filterTemplate">
58
+ <div class="quiet">
59
+ Filter:
60
+ <input type="search" id="fileSearch">
61
+ </div>
62
+ </template>
63
+ </div>
64
+ <div class='status-line low'></div>
65
+ <pre><table class="coverage">
66
+ <tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
67
+ <a name='L2'></a><a href='#L2'>2</a>
68
+ <a name='L3'></a><a href='#L3'>3</a>
69
+ <a name='L4'></a><a href='#L4'>4</a>
70
+ <a name='L5'></a><a href='#L5'>5</a>
71
+ <a name='L6'></a><a href='#L6'>6</a>
72
+ <a name='L7'></a><a href='#L7'>7</a>
73
+ <a name='L8'></a><a href='#L8'>8</a>
74
+ <a name='L9'></a><a href='#L9'>9</a>
75
+ <a name='L10'></a><a href='#L10'>10</a>
76
+ <a name='L11'></a><a href='#L11'>11</a>
77
+ <a name='L12'></a><a href='#L12'>12</a>
78
+ <a name='L13'></a><a href='#L13'>13</a>
79
+ <a name='L14'></a><a href='#L14'>14</a>
80
+ <a name='L15'></a><a href='#L15'>15</a>
81
+ <a name='L16'></a><a href='#L16'>16</a>
82
+ <a name='L17'></a><a href='#L17'>17</a>
83
+ <a name='L18'></a><a href='#L18'>18</a>
84
+ <a name='L19'></a><a href='#L19'>19</a>
85
+ <a name='L20'></a><a href='#L20'>20</a>
86
+ <a name='L21'></a><a href='#L21'>21</a>
87
+ <a name='L22'></a><a href='#L22'>22</a>
88
+ <a name='L23'></a><a href='#L23'>23</a>
89
+ <a name='L24'></a><a href='#L24'>24</a>
90
+ <a name='L25'></a><a href='#L25'>25</a>
91
+ <a name='L26'></a><a href='#L26'>26</a>
92
+ <a name='L27'></a><a href='#L27'>27</a>
93
+ <a name='L28'></a><a href='#L28'>28</a>
94
+ <a name='L29'></a><a href='#L29'>29</a>
95
+ <a name='L30'></a><a href='#L30'>30</a>
96
+ <a name='L31'></a><a href='#L31'>31</a>
97
+ <a name='L32'></a><a href='#L32'>32</a>
98
+ <a name='L33'></a><a href='#L33'>33</a>
99
+ <a name='L34'></a><a href='#L34'>34</a>
100
+ <a name='L35'></a><a href='#L35'>35</a>
101
+ <a name='L36'></a><a href='#L36'>36</a>
102
+ <a name='L37'></a><a href='#L37'>37</a>
103
+ <a name='L38'></a><a href='#L38'>38</a>
104
+ <a name='L39'></a><a href='#L39'>39</a>
105
+ <a name='L40'></a><a href='#L40'>40</a>
106
+ <a name='L41'></a><a href='#L41'>41</a>
107
+ <a name='L42'></a><a href='#L42'>42</a>
108
+ <a name='L43'></a><a href='#L43'>43</a>
109
+ <a name='L44'></a><a href='#L44'>44</a>
110
+ <a name='L45'></a><a href='#L45'>45</a>
111
+ <a name='L46'></a><a href='#L46'>46</a>
112
+ <a name='L47'></a><a href='#L47'>47</a>
113
+ <a name='L48'></a><a href='#L48'>48</a>
114
+ <a name='L49'></a><a href='#L49'>49</a>
115
+ <a name='L50'></a><a href='#L50'>50</a>
116
+ <a name='L51'></a><a href='#L51'>51</a>
117
+ <a name='L52'></a><a href='#L52'>52</a>
118
+ <a name='L53'></a><a href='#L53'>53</a>
119
+ <a name='L54'></a><a href='#L54'>54</a>
120
+ <a name='L55'></a><a href='#L55'>55</a>
121
+ <a name='L56'></a><a href='#L56'>56</a>
122
+ <a name='L57'></a><a href='#L57'>57</a>
123
+ <a name='L58'></a><a href='#L58'>58</a>
124
+ <a name='L59'></a><a href='#L59'>59</a>
125
+ <a name='L60'></a><a href='#L60'>60</a>
126
+ <a name='L61'></a><a href='#L61'>61</a>
127
+ <a name='L62'></a><a href='#L62'>62</a>
128
+ <a name='L63'></a><a href='#L63'>63</a>
129
+ <a name='L64'></a><a href='#L64'>64</a>
130
+ <a name='L65'></a><a href='#L65'>65</a>
131
+ <a name='L66'></a><a href='#L66'>66</a>
132
+ <a name='L67'></a><a href='#L67'>67</a>
133
+ <a name='L68'></a><a href='#L68'>68</a>
134
+ <a name='L69'></a><a href='#L69'>69</a>
135
+ <a name='L70'></a><a href='#L70'>70</a>
136
+ <a name='L71'></a><a href='#L71'>71</a>
137
+ <a name='L72'></a><a href='#L72'>72</a>
138
+ <a name='L73'></a><a href='#L73'>73</a>
139
+ <a name='L74'></a><a href='#L74'>74</a>
140
+ <a name='L75'></a><a href='#L75'>75</a>
141
+ <a name='L76'></a><a href='#L76'>76</a>
142
+ <a name='L77'></a><a href='#L77'>77</a>
143
+ <a name='L78'></a><a href='#L78'>78</a>
144
+ <a name='L79'></a><a href='#L79'>79</a>
145
+ <a name='L80'></a><a href='#L80'>80</a>
146
+ <a name='L81'></a><a href='#L81'>81</a>
147
+ <a name='L82'></a><a href='#L82'>82</a>
148
+ <a name='L83'></a><a href='#L83'>83</a>
149
+ <a name='L84'></a><a href='#L84'>84</a>
150
+ <a name='L85'></a><a href='#L85'>85</a>
151
+ <a name='L86'></a><a href='#L86'>86</a>
152
+ <a name='L87'></a><a href='#L87'>87</a>
153
+ <a name='L88'></a><a href='#L88'>88</a>
154
+ <a name='L89'></a><a href='#L89'>89</a>
155
+ <a name='L90'></a><a href='#L90'>90</a>
156
+ <a name='L91'></a><a href='#L91'>91</a>
157
+ <a name='L92'></a><a href='#L92'>92</a>
158
+ <a name='L93'></a><a href='#L93'>93</a>
159
+ <a name='L94'></a><a href='#L94'>94</a>
160
+ <a name='L95'></a><a href='#L95'>95</a>
161
+ <a name='L96'></a><a href='#L96'>96</a>
162
+ <a name='L97'></a><a href='#L97'>97</a>
163
+ <a name='L98'></a><a href='#L98'>98</a>
164
+ <a name='L99'></a><a href='#L99'>99</a>
165
+ <a name='L100'></a><a href='#L100'>100</a>
166
+ <a name='L101'></a><a href='#L101'>101</a>
167
+ <a name='L102'></a><a href='#L102'>102</a>
168
+ <a name='L103'></a><a href='#L103'>103</a>
169
+ <a name='L104'></a><a href='#L104'>104</a>
170
+ <a name='L105'></a><a href='#L105'>105</a>
171
+ <a name='L106'></a><a href='#L106'>106</a>
172
+ <a name='L107'></a><a href='#L107'>107</a>
173
+ <a name='L108'></a><a href='#L108'>108</a>
174
+ <a name='L109'></a><a href='#L109'>109</a>
175
+ <a name='L110'></a><a href='#L110'>110</a>
176
+ <a name='L111'></a><a href='#L111'>111</a>
177
+ <a name='L112'></a><a href='#L112'>112</a>
178
+ <a name='L113'></a><a href='#L113'>113</a>
179
+ <a name='L114'></a><a href='#L114'>114</a>
180
+ <a name='L115'></a><a href='#L115'>115</a>
181
+ <a name='L116'></a><a href='#L116'>116</a>
182
+ <a name='L117'></a><a href='#L117'>117</a>
183
+ <a name='L118'></a><a href='#L118'>118</a>
184
+ <a name='L119'></a><a href='#L119'>119</a>
185
+ <a name='L120'></a><a href='#L120'>120</a>
186
+ <a name='L121'></a><a href='#L121'>121</a>
187
+ <a name='L122'></a><a href='#L122'>122</a>
188
+ <a name='L123'></a><a href='#L123'>123</a>
189
+ <a name='L124'></a><a href='#L124'>124</a>
190
+ <a name='L125'></a><a href='#L125'>125</a>
191
+ <a name='L126'></a><a href='#L126'>126</a>
192
+ <a name='L127'></a><a href='#L127'>127</a>
193
+ <a name='L128'></a><a href='#L128'>128</a>
194
+ <a name='L129'></a><a href='#L129'>129</a>
195
+ <a name='L130'></a><a href='#L130'>130</a>
196
+ <a name='L131'></a><a href='#L131'>131</a>
197
+ <a name='L132'></a><a href='#L132'>132</a>
198
+ <a name='L133'></a><a href='#L133'>133</a>
199
+ <a name='L134'></a><a href='#L134'>134</a>
200
+ <a name='L135'></a><a href='#L135'>135</a>
201
+ <a name='L136'></a><a href='#L136'>136</a>
202
+ <a name='L137'></a><a href='#L137'>137</a>
203
+ <a name='L138'></a><a href='#L138'>138</a>
204
+ <a name='L139'></a><a href='#L139'>139</a>
205
+ <a name='L140'></a><a href='#L140'>140</a>
206
+ <a name='L141'></a><a href='#L141'>141</a>
207
+ <a name='L142'></a><a href='#L142'>142</a>
208
+ <a name='L143'></a><a href='#L143'>143</a>
209
+ <a name='L144'></a><a href='#L144'>144</a>
210
+ <a name='L145'></a><a href='#L145'>145</a>
211
+ <a name='L146'></a><a href='#L146'>146</a>
212
+ <a name='L147'></a><a href='#L147'>147</a>
213
+ <a name='L148'></a><a href='#L148'>148</a>
214
+ <a name='L149'></a><a href='#L149'>149</a>
215
+ <a name='L150'></a><a href='#L150'>150</a>
216
+ <a name='L151'></a><a href='#L151'>151</a>
217
+ <a name='L152'></a><a href='#L152'>152</a>
218
+ <a name='L153'></a><a href='#L153'>153</a>
219
+ <a name='L154'></a><a href='#L154'>154</a>
220
+ <a name='L155'></a><a href='#L155'>155</a>
221
+ <a name='L156'></a><a href='#L156'>156</a>
222
+ <a name='L157'></a><a href='#L157'>157</a>
223
+ <a name='L158'></a><a href='#L158'>158</a>
224
+ <a name='L159'></a><a href='#L159'>159</a>
225
+ <a name='L160'></a><a href='#L160'>160</a>
226
+ <a name='L161'></a><a href='#L161'>161</a>
227
+ <a name='L162'></a><a href='#L162'>162</a>
228
+ <a name='L163'></a><a href='#L163'>163</a>
229
+ <a name='L164'></a><a href='#L164'>164</a>
230
+ <a name='L165'></a><a href='#L165'>165</a>
231
+ <a name='L166'></a><a href='#L166'>166</a>
232
+ <a name='L167'></a><a href='#L167'>167</a>
233
+ <a name='L168'></a><a href='#L168'>168</a>
234
+ <a name='L169'></a><a href='#L169'>169</a>
235
+ <a name='L170'></a><a href='#L170'>170</a>
236
+ <a name='L171'></a><a href='#L171'>171</a>
237
+ <a name='L172'></a><a href='#L172'>172</a>
238
+ <a name='L173'></a><a href='#L173'>173</a>
239
+ <a name='L174'></a><a href='#L174'>174</a>
240
+ <a name='L175'></a><a href='#L175'>175</a>
241
+ <a name='L176'></a><a href='#L176'>176</a>
242
+ <a name='L177'></a><a href='#L177'>177</a>
243
+ <a name='L178'></a><a href='#L178'>178</a>
244
+ <a name='L179'></a><a href='#L179'>179</a>
245
+ <a name='L180'></a><a href='#L180'>180</a>
246
+ <a name='L181'></a><a href='#L181'>181</a>
247
+ <a name='L182'></a><a href='#L182'>182</a>
248
+ <a name='L183'></a><a href='#L183'>183</a>
249
+ <a name='L184'></a><a href='#L184'>184</a>
250
+ <a name='L185'></a><a href='#L185'>185</a>
251
+ <a name='L186'></a><a href='#L186'>186</a>
252
+ <a name='L187'></a><a href='#L187'>187</a>
253
+ <a name='L188'></a><a href='#L188'>188</a>
254
+ <a name='L189'></a><a href='#L189'>189</a>
255
+ <a name='L190'></a><a href='#L190'>190</a>
256
+ <a name='L191'></a><a href='#L191'>191</a>
257
+ <a name='L192'></a><a href='#L192'>192</a>
258
+ <a name='L193'></a><a href='#L193'>193</a>
259
+ <a name='L194'></a><a href='#L194'>194</a>
260
+ <a name='L195'></a><a href='#L195'>195</a>
261
+ <a name='L196'></a><a href='#L196'>196</a>
262
+ <a name='L197'></a><a href='#L197'>197</a>
263
+ <a name='L198'></a><a href='#L198'>198</a>
264
+ <a name='L199'></a><a href='#L199'>199</a>
265
+ <a name='L200'></a><a href='#L200'>200</a>
266
+ <a name='L201'></a><a href='#L201'>201</a>
267
+ <a name='L202'></a><a href='#L202'>202</a>
268
+ <a name='L203'></a><a href='#L203'>203</a>
269
+ <a name='L204'></a><a href='#L204'>204</a>
270
+ <a name='L205'></a><a href='#L205'>205</a>
271
+ <a name='L206'></a><a href='#L206'>206</a>
272
+ <a name='L207'></a><a href='#L207'>207</a>
273
+ <a name='L208'></a><a href='#L208'>208</a>
274
+ <a name='L209'></a><a href='#L209'>209</a>
275
+ <a name='L210'></a><a href='#L210'>210</a>
276
+ <a name='L211'></a><a href='#L211'>211</a>
277
+ <a name='L212'></a><a href='#L212'>212</a>
278
+ <a name='L213'></a><a href='#L213'>213</a>
279
+ <a name='L214'></a><a href='#L214'>214</a>
280
+ <a name='L215'></a><a href='#L215'>215</a>
281
+ <a name='L216'></a><a href='#L216'>216</a>
282
+ <a name='L217'></a><a href='#L217'>217</a>
283
+ <a name='L218'></a><a href='#L218'>218</a>
284
+ <a name='L219'></a><a href='#L219'>219</a>
285
+ <a name='L220'></a><a href='#L220'>220</a>
286
+ <a name='L221'></a><a href='#L221'>221</a>
287
+ <a name='L222'></a><a href='#L222'>222</a>
288
+ <a name='L223'></a><a href='#L223'>223</a>
289
+ <a name='L224'></a><a href='#L224'>224</a>
290
+ <a name='L225'></a><a href='#L225'>225</a>
291
+ <a name='L226'></a><a href='#L226'>226</a>
292
+ <a name='L227'></a><a href='#L227'>227</a>
293
+ <a name='L228'></a><a href='#L228'>228</a>
294
+ <a name='L229'></a><a href='#L229'>229</a>
295
+ <a name='L230'></a><a href='#L230'>230</a>
296
+ <a name='L231'></a><a href='#L231'>231</a>
297
+ <a name='L232'></a><a href='#L232'>232</a>
298
+ <a name='L233'></a><a href='#L233'>233</a>
299
+ <a name='L234'></a><a href='#L234'>234</a>
300
+ <a name='L235'></a><a href='#L235'>235</a>
301
+ <a name='L236'></a><a href='#L236'>236</a>
302
+ <a name='L237'></a><a href='#L237'>237</a>
303
+ <a name='L238'></a><a href='#L238'>238</a>
304
+ <a name='L239'></a><a href='#L239'>239</a>
305
+ <a name='L240'></a><a href='#L240'>240</a>
306
+ <a name='L241'></a><a href='#L241'>241</a>
307
+ <a name='L242'></a><a href='#L242'>242</a>
308
+ <a name='L243'></a><a href='#L243'>243</a>
309
+ <a name='L244'></a><a href='#L244'>244</a>
310
+ <a name='L245'></a><a href='#L245'>245</a>
311
+ <a name='L246'></a><a href='#L246'>246</a>
312
+ <a name='L247'></a><a href='#L247'>247</a>
313
+ <a name='L248'></a><a href='#L248'>248</a>
314
+ <a name='L249'></a><a href='#L249'>249</a>
315
+ <a name='L250'></a><a href='#L250'>250</a>
316
+ <a name='L251'></a><a href='#L251'>251</a>
317
+ <a name='L252'></a><a href='#L252'>252</a>
318
+ <a name='L253'></a><a href='#L253'>253</a>
319
+ <a name='L254'></a><a href='#L254'>254</a>
320
+ <a name='L255'></a><a href='#L255'>255</a>
321
+ <a name='L256'></a><a href='#L256'>256</a>
322
+ <a name='L257'></a><a href='#L257'>257</a>
323
+ <a name='L258'></a><a href='#L258'>258</a>
324
+ <a name='L259'></a><a href='#L259'>259</a>
325
+ <a name='L260'></a><a href='#L260'>260</a>
326
+ <a name='L261'></a><a href='#L261'>261</a>
327
+ <a name='L262'></a><a href='#L262'>262</a>
328
+ <a name='L263'></a><a href='#L263'>263</a>
329
+ <a name='L264'></a><a href='#L264'>264</a>
330
+ <a name='L265'></a><a href='#L265'>265</a>
331
+ <a name='L266'></a><a href='#L266'>266</a>
332
+ <a name='L267'></a><a href='#L267'>267</a>
333
+ <a name='L268'></a><a href='#L268'>268</a>
334
+ <a name='L269'></a><a href='#L269'>269</a>
335
+ <a name='L270'></a><a href='#L270'>270</a>
336
+ <a name='L271'></a><a href='#L271'>271</a>
337
+ <a name='L272'></a><a href='#L272'>272</a>
338
+ <a name='L273'></a><a href='#L273'>273</a>
339
+ <a name='L274'></a><a href='#L274'>274</a>
340
+ <a name='L275'></a><a href='#L275'>275</a>
341
+ <a name='L276'></a><a href='#L276'>276</a>
342
+ <a name='L277'></a><a href='#L277'>277</a>
343
+ <a name='L278'></a><a href='#L278'>278</a>
344
+ <a name='L279'></a><a href='#L279'>279</a>
345
+ <a name='L280'></a><a href='#L280'>280</a>
346
+ <a name='L281'></a><a href='#L281'>281</a>
347
+ <a name='L282'></a><a href='#L282'>282</a>
348
+ <a name='L283'></a><a href='#L283'>283</a>
349
+ <a name='L284'></a><a href='#L284'>284</a>
350
+ <a name='L285'></a><a href='#L285'>285</a>
351
+ <a name='L286'></a><a href='#L286'>286</a>
352
+ <a name='L287'></a><a href='#L287'>287</a>
353
+ <a name='L288'></a><a href='#L288'>288</a>
354
+ <a name='L289'></a><a href='#L289'>289</a>
355
+ <a name='L290'></a><a href='#L290'>290</a>
356
+ <a name='L291'></a><a href='#L291'>291</a>
357
+ <a name='L292'></a><a href='#L292'>292</a>
358
+ <a name='L293'></a><a href='#L293'>293</a>
359
+ <a name='L294'></a><a href='#L294'>294</a>
360
+ <a name='L295'></a><a href='#L295'>295</a>
361
+ <a name='L296'></a><a href='#L296'>296</a>
362
+ <a name='L297'></a><a href='#L297'>297</a>
363
+ <a name='L298'></a><a href='#L298'>298</a>
364
+ <a name='L299'></a><a href='#L299'>299</a>
365
+ <a name='L300'></a><a href='#L300'>300</a>
366
+ <a name='L301'></a><a href='#L301'>301</a>
367
+ <a name='L302'></a><a href='#L302'>302</a>
368
+ <a name='L303'></a><a href='#L303'>303</a>
369
+ <a name='L304'></a><a href='#L304'>304</a>
370
+ <a name='L305'></a><a href='#L305'>305</a>
371
+ <a name='L306'></a><a href='#L306'>306</a>
372
+ <a name='L307'></a><a href='#L307'>307</a>
373
+ <a name='L308'></a><a href='#L308'>308</a>
374
+ <a name='L309'></a><a href='#L309'>309</a>
375
+ <a name='L310'></a><a href='#L310'>310</a>
376
+ <a name='L311'></a><a href='#L311'>311</a>
377
+ <a name='L312'></a><a href='#L312'>312</a>
378
+ <a name='L313'></a><a href='#L313'>313</a>
379
+ <a name='L314'></a><a href='#L314'>314</a>
380
+ <a name='L315'></a><a href='#L315'>315</a>
381
+ <a name='L316'></a><a href='#L316'>316</a>
382
+ <a name='L317'></a><a href='#L317'>317</a>
383
+ <a name='L318'></a><a href='#L318'>318</a>
384
+ <a name='L319'></a><a href='#L319'>319</a>
385
+ <a name='L320'></a><a href='#L320'>320</a>
386
+ <a name='L321'></a><a href='#L321'>321</a>
387
+ <a name='L322'></a><a href='#L322'>322</a>
388
+ <a name='L323'></a><a href='#L323'>323</a>
389
+ <a name='L324'></a><a href='#L324'>324</a>
390
+ <a name='L325'></a><a href='#L325'>325</a>
391
+ <a name='L326'></a><a href='#L326'>326</a>
392
+ <a name='L327'></a><a href='#L327'>327</a>
393
+ <a name='L328'></a><a href='#L328'>328</a>
394
+ <a name='L329'></a><a href='#L329'>329</a>
395
+ <a name='L330'></a><a href='#L330'>330</a>
396
+ <a name='L331'></a><a href='#L331'>331</a>
397
+ <a name='L332'></a><a href='#L332'>332</a>
398
+ <a name='L333'></a><a href='#L333'>333</a>
399
+ <a name='L334'></a><a href='#L334'>334</a>
400
+ <a name='L335'></a><a href='#L335'>335</a>
401
+ <a name='L336'></a><a href='#L336'>336</a>
402
+ <a name='L337'></a><a href='#L337'>337</a>
403
+ <a name='L338'></a><a href='#L338'>338</a>
404
+ <a name='L339'></a><a href='#L339'>339</a>
405
+ <a name='L340'></a><a href='#L340'>340</a>
406
+ <a name='L341'></a><a href='#L341'>341</a>
407
+ <a name='L342'></a><a href='#L342'>342</a>
408
+ <a name='L343'></a><a href='#L343'>343</a>
409
+ <a name='L344'></a><a href='#L344'>344</a>
410
+ <a name='L345'></a><a href='#L345'>345</a>
411
+ <a name='L346'></a><a href='#L346'>346</a>
412
+ <a name='L347'></a><a href='#L347'>347</a>
413
+ <a name='L348'></a><a href='#L348'>348</a>
414
+ <a name='L349'></a><a href='#L349'>349</a>
415
+ <a name='L350'></a><a href='#L350'>350</a>
416
+ <a name='L351'></a><a href='#L351'>351</a>
417
+ <a name='L352'></a><a href='#L352'>352</a>
418
+ <a name='L353'></a><a href='#L353'>353</a>
419
+ <a name='L354'></a><a href='#L354'>354</a>
420
+ <a name='L355'></a><a href='#L355'>355</a>
421
+ <a name='L356'></a><a href='#L356'>356</a>
422
+ <a name='L357'></a><a href='#L357'>357</a>
423
+ <a name='L358'></a><a href='#L358'>358</a>
424
+ <a name='L359'></a><a href='#L359'>359</a>
425
+ <a name='L360'></a><a href='#L360'>360</a>
426
+ <a name='L361'></a><a href='#L361'>361</a>
427
+ <a name='L362'></a><a href='#L362'>362</a>
428
+ <a name='L363'></a><a href='#L363'>363</a>
429
+ <a name='L364'></a><a href='#L364'>364</a>
430
+ <a name='L365'></a><a href='#L365'>365</a>
431
+ <a name='L366'></a><a href='#L366'>366</a>
432
+ <a name='L367'></a><a href='#L367'>367</a>
433
+ <a name='L368'></a><a href='#L368'>368</a>
434
+ <a name='L369'></a><a href='#L369'>369</a>
435
+ <a name='L370'></a><a href='#L370'>370</a>
436
+ <a name='L371'></a><a href='#L371'>371</a>
437
+ <a name='L372'></a><a href='#L372'>372</a>
438
+ <a name='L373'></a><a href='#L373'>373</a>
439
+ <a name='L374'></a><a href='#L374'>374</a>
440
+ <a name='L375'></a><a href='#L375'>375</a>
441
+ <a name='L376'></a><a href='#L376'>376</a>
442
+ <a name='L377'></a><a href='#L377'>377</a>
443
+ <a name='L378'></a><a href='#L378'>378</a>
444
+ <a name='L379'></a><a href='#L379'>379</a>
445
+ <a name='L380'></a><a href='#L380'>380</a>
446
+ <a name='L381'></a><a href='#L381'>381</a>
447
+ <a name='L382'></a><a href='#L382'>382</a>
448
+ <a name='L383'></a><a href='#L383'>383</a>
449
+ <a name='L384'></a><a href='#L384'>384</a>
450
+ <a name='L385'></a><a href='#L385'>385</a>
451
+ <a name='L386'></a><a href='#L386'>386</a>
452
+ <a name='L387'></a><a href='#L387'>387</a>
453
+ <a name='L388'></a><a href='#L388'>388</a>
454
+ <a name='L389'></a><a href='#L389'>389</a>
455
+ <a name='L390'></a><a href='#L390'>390</a>
456
+ <a name='L391'></a><a href='#L391'>391</a>
457
+ <a name='L392'></a><a href='#L392'>392</a>
458
+ <a name='L393'></a><a href='#L393'>393</a>
459
+ <a name='L394'></a><a href='#L394'>394</a>
460
+ <a name='L395'></a><a href='#L395'>395</a>
461
+ <a name='L396'></a><a href='#L396'>396</a>
462
+ <a name='L397'></a><a href='#L397'>397</a>
463
+ <a name='L398'></a><a href='#L398'>398</a>
464
+ <a name='L399'></a><a href='#L399'>399</a>
465
+ <a name='L400'></a><a href='#L400'>400</a>
466
+ <a name='L401'></a><a href='#L401'>401</a>
467
+ <a name='L402'></a><a href='#L402'>402</a>
468
+ <a name='L403'></a><a href='#L403'>403</a>
469
+ <a name='L404'></a><a href='#L404'>404</a>
470
+ <a name='L405'></a><a href='#L405'>405</a>
471
+ <a name='L406'></a><a href='#L406'>406</a>
472
+ <a name='L407'></a><a href='#L407'>407</a>
473
+ <a name='L408'></a><a href='#L408'>408</a>
474
+ <a name='L409'></a><a href='#L409'>409</a>
475
+ <a name='L410'></a><a href='#L410'>410</a>
476
+ <a name='L411'></a><a href='#L411'>411</a>
477
+ <a name='L412'></a><a href='#L412'>412</a>
478
+ <a name='L413'></a><a href='#L413'>413</a>
479
+ <a name='L414'></a><a href='#L414'>414</a>
480
+ <a name='L415'></a><a href='#L415'>415</a>
481
+ <a name='L416'></a><a href='#L416'>416</a>
482
+ <a name='L417'></a><a href='#L417'>417</a>
483
+ <a name='L418'></a><a href='#L418'>418</a>
484
+ <a name='L419'></a><a href='#L419'>419</a>
485
+ <a name='L420'></a><a href='#L420'>420</a>
486
+ <a name='L421'></a><a href='#L421'>421</a>
487
+ <a name='L422'></a><a href='#L422'>422</a>
488
+ <a name='L423'></a><a href='#L423'>423</a>
489
+ <a name='L424'></a><a href='#L424'>424</a>
490
+ <a name='L425'></a><a href='#L425'>425</a>
491
+ <a name='L426'></a><a href='#L426'>426</a>
492
+ <a name='L427'></a><a href='#L427'>427</a>
493
+ <a name='L428'></a><a href='#L428'>428</a>
494
+ <a name='L429'></a><a href='#L429'>429</a>
495
+ <a name='L430'></a><a href='#L430'>430</a>
496
+ <a name='L431'></a><a href='#L431'>431</a>
497
+ <a name='L432'></a><a href='#L432'>432</a>
498
+ <a name='L433'></a><a href='#L433'>433</a>
499
+ <a name='L434'></a><a href='#L434'>434</a>
500
+ <a name='L435'></a><a href='#L435'>435</a>
501
+ <a name='L436'></a><a href='#L436'>436</a>
502
+ <a name='L437'></a><a href='#L437'>437</a>
503
+ <a name='L438'></a><a href='#L438'>438</a>
504
+ <a name='L439'></a><a href='#L439'>439</a>
505
+ <a name='L440'></a><a href='#L440'>440</a>
506
+ <a name='L441'></a><a href='#L441'>441</a>
507
+ <a name='L442'></a><a href='#L442'>442</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
508
+ <span class="cline-any cline-neutral">&nbsp;</span>
509
+ <span class="cline-any cline-neutral">&nbsp;</span>
510
+ <span class="cline-any cline-neutral">&nbsp;</span>
511
+ <span class="cline-any cline-neutral">&nbsp;</span>
512
+ <span class="cline-any cline-neutral">&nbsp;</span>
513
+ <span class="cline-any cline-neutral">&nbsp;</span>
514
+ <span class="cline-any cline-neutral">&nbsp;</span>
515
+ <span class="cline-any cline-neutral">&nbsp;</span>
516
+ <span class="cline-any cline-neutral">&nbsp;</span>
517
+ <span class="cline-any cline-yes">1x</span>
518
+ <span class="cline-any cline-neutral">&nbsp;</span>
519
+ <span class="cline-any cline-neutral">&nbsp;</span>
520
+ <span class="cline-any cline-neutral">&nbsp;</span>
521
+ <span class="cline-any cline-neutral">&nbsp;</span>
522
+ <span class="cline-any cline-yes">1x</span>
523
+ <span class="cline-any cline-yes">1x</span>
524
+ <span class="cline-any cline-neutral">&nbsp;</span>
525
+ <span class="cline-any cline-yes">1x</span>
526
+ <span class="cline-any cline-yes">1x</span>
527
+ <span class="cline-any cline-neutral">&nbsp;</span>
528
+ <span class="cline-any cline-yes">1x</span>
529
+ <span class="cline-any cline-neutral">&nbsp;</span>
530
+ <span class="cline-any cline-no">&nbsp;</span>
531
+ <span class="cline-any cline-neutral">&nbsp;</span>
532
+ <span class="cline-any cline-neutral">&nbsp;</span>
533
+ <span class="cline-any cline-neutral">&nbsp;</span>
534
+ <span class="cline-any cline-neutral">&nbsp;</span>
535
+ <span class="cline-any cline-neutral">&nbsp;</span>
536
+ <span class="cline-any cline-no">&nbsp;</span>
537
+ <span class="cline-any cline-neutral">&nbsp;</span>
538
+ <span class="cline-any cline-neutral">&nbsp;</span>
539
+ <span class="cline-any cline-neutral">&nbsp;</span>
540
+ <span class="cline-any cline-neutral">&nbsp;</span>
541
+ <span class="cline-any cline-neutral">&nbsp;</span>
542
+ <span class="cline-any cline-no">&nbsp;</span>
543
+ <span class="cline-any cline-neutral">&nbsp;</span>
544
+ <span class="cline-any cline-neutral">&nbsp;</span>
545
+ <span class="cline-any cline-neutral">&nbsp;</span>
546
+ <span class="cline-any cline-neutral">&nbsp;</span>
547
+ <span class="cline-any cline-neutral">&nbsp;</span>
548
+ <span class="cline-any cline-neutral">&nbsp;</span>
549
+ <span class="cline-any cline-no">&nbsp;</span>
550
+ <span class="cline-any cline-neutral">&nbsp;</span>
551
+ <span class="cline-any cline-neutral">&nbsp;</span>
552
+ <span class="cline-any cline-no">&nbsp;</span>
553
+ <span class="cline-any cline-neutral">&nbsp;</span>
554
+ <span class="cline-any cline-neutral">&nbsp;</span>
555
+ <span class="cline-any cline-no">&nbsp;</span>
556
+ <span class="cline-any cline-neutral">&nbsp;</span>
557
+ <span class="cline-any cline-neutral">&nbsp;</span>
558
+ <span class="cline-any cline-no">&nbsp;</span>
559
+ <span class="cline-any cline-no">&nbsp;</span>
560
+ <span class="cline-any cline-neutral">&nbsp;</span>
561
+ <span class="cline-any cline-no">&nbsp;</span>
562
+ <span class="cline-any cline-no">&nbsp;</span>
563
+ <span class="cline-any cline-no">&nbsp;</span>
564
+ <span class="cline-any cline-no">&nbsp;</span>
565
+ <span class="cline-any cline-no">&nbsp;</span>
566
+ <span class="cline-any cline-no">&nbsp;</span>
567
+ <span class="cline-any cline-neutral">&nbsp;</span>
568
+ <span class="cline-any cline-no">&nbsp;</span>
569
+ <span class="cline-any cline-neutral">&nbsp;</span>
570
+ <span class="cline-any cline-neutral">&nbsp;</span>
571
+ <span class="cline-any cline-no">&nbsp;</span>
572
+ <span class="cline-any cline-no">&nbsp;</span>
573
+ <span class="cline-any cline-neutral">&nbsp;</span>
574
+ <span class="cline-any cline-neutral">&nbsp;</span>
575
+ <span class="cline-any cline-no">&nbsp;</span>
576
+ <span class="cline-any cline-no">&nbsp;</span>
577
+ <span class="cline-any cline-no">&nbsp;</span>
578
+ <span class="cline-any cline-no">&nbsp;</span>
579
+ <span class="cline-any cline-no">&nbsp;</span>
580
+ <span class="cline-any cline-no">&nbsp;</span>
581
+ <span class="cline-any cline-no">&nbsp;</span>
582
+ <span class="cline-any cline-no">&nbsp;</span>
583
+ <span class="cline-any cline-no">&nbsp;</span>
584
+ <span class="cline-any cline-no">&nbsp;</span>
585
+ <span class="cline-any cline-no">&nbsp;</span>
586
+ <span class="cline-any cline-no">&nbsp;</span>
587
+ <span class="cline-any cline-no">&nbsp;</span>
588
+ <span class="cline-any cline-no">&nbsp;</span>
589
+ <span class="cline-any cline-neutral">&nbsp;</span>
590
+ <span class="cline-any cline-neutral">&nbsp;</span>
591
+ <span class="cline-any cline-no">&nbsp;</span>
592
+ <span class="cline-any cline-no">&nbsp;</span>
593
+ <span class="cline-any cline-no">&nbsp;</span>
594
+ <span class="cline-any cline-no">&nbsp;</span>
595
+ <span class="cline-any cline-no">&nbsp;</span>
596
+ <span class="cline-any cline-no">&nbsp;</span>
597
+ <span class="cline-any cline-no">&nbsp;</span>
598
+ <span class="cline-any cline-no">&nbsp;</span>
599
+ <span class="cline-any cline-no">&nbsp;</span>
600
+ <span class="cline-any cline-no">&nbsp;</span>
601
+ <span class="cline-any cline-neutral">&nbsp;</span>
602
+ <span class="cline-any cline-neutral">&nbsp;</span>
603
+ <span class="cline-any cline-no">&nbsp;</span>
604
+ <span class="cline-any cline-no">&nbsp;</span>
605
+ <span class="cline-any cline-no">&nbsp;</span>
606
+ <span class="cline-any cline-no">&nbsp;</span>
607
+ <span class="cline-any cline-no">&nbsp;</span>
608
+ <span class="cline-any cline-no">&nbsp;</span>
609
+ <span class="cline-any cline-no">&nbsp;</span>
610
+ <span class="cline-any cline-no">&nbsp;</span>
611
+ <span class="cline-any cline-no">&nbsp;</span>
612
+ <span class="cline-any cline-no">&nbsp;</span>
613
+ <span class="cline-any cline-no">&nbsp;</span>
614
+ <span class="cline-any cline-no">&nbsp;</span>
615
+ <span class="cline-any cline-no">&nbsp;</span>
616
+ <span class="cline-any cline-no">&nbsp;</span>
617
+ <span class="cline-any cline-neutral">&nbsp;</span>
618
+ <span class="cline-any cline-neutral">&nbsp;</span>
619
+ <span class="cline-any cline-no">&nbsp;</span>
620
+ <span class="cline-any cline-no">&nbsp;</span>
621
+ <span class="cline-any cline-no">&nbsp;</span>
622
+ <span class="cline-any cline-no">&nbsp;</span>
623
+ <span class="cline-any cline-no">&nbsp;</span>
624
+ <span class="cline-any cline-no">&nbsp;</span>
625
+ <span class="cline-any cline-neutral">&nbsp;</span>
626
+ <span class="cline-any cline-neutral">&nbsp;</span>
627
+ <span class="cline-any cline-no">&nbsp;</span>
628
+ <span class="cline-any cline-no">&nbsp;</span>
629
+ <span class="cline-any cline-no">&nbsp;</span>
630
+ <span class="cline-any cline-no">&nbsp;</span>
631
+ <span class="cline-any cline-no">&nbsp;</span>
632
+ <span class="cline-any cline-no">&nbsp;</span>
633
+ <span class="cline-any cline-no">&nbsp;</span>
634
+ <span class="cline-any cline-no">&nbsp;</span>
635
+ <span class="cline-any cline-no">&nbsp;</span>
636
+ <span class="cline-any cline-no">&nbsp;</span>
637
+ <span class="cline-any cline-no">&nbsp;</span>
638
+ <span class="cline-any cline-no">&nbsp;</span>
639
+ <span class="cline-any cline-no">&nbsp;</span>
640
+ <span class="cline-any cline-no">&nbsp;</span>
641
+ <span class="cline-any cline-neutral">&nbsp;</span>
642
+ <span class="cline-any cline-neutral">&nbsp;</span>
643
+ <span class="cline-any cline-no">&nbsp;</span>
644
+ <span class="cline-any cline-no">&nbsp;</span>
645
+ <span class="cline-any cline-no">&nbsp;</span>
646
+ <span class="cline-any cline-no">&nbsp;</span>
647
+ <span class="cline-any cline-no">&nbsp;</span>
648
+ <span class="cline-any cline-no">&nbsp;</span>
649
+ <span class="cline-any cline-neutral">&nbsp;</span>
650
+ <span class="cline-any cline-neutral">&nbsp;</span>
651
+ <span class="cline-any cline-no">&nbsp;</span>
652
+ <span class="cline-any cline-no">&nbsp;</span>
653
+ <span class="cline-any cline-no">&nbsp;</span>
654
+ <span class="cline-any cline-no">&nbsp;</span>
655
+ <span class="cline-any cline-no">&nbsp;</span>
656
+ <span class="cline-any cline-no">&nbsp;</span>
657
+ <span class="cline-any cline-neutral">&nbsp;</span>
658
+ <span class="cline-any cline-neutral">&nbsp;</span>
659
+ <span class="cline-any cline-no">&nbsp;</span>
660
+ <span class="cline-any cline-no">&nbsp;</span>
661
+ <span class="cline-any cline-no">&nbsp;</span>
662
+ <span class="cline-any cline-no">&nbsp;</span>
663
+ <span class="cline-any cline-no">&nbsp;</span>
664
+ <span class="cline-any cline-no">&nbsp;</span>
665
+ <span class="cline-any cline-neutral">&nbsp;</span>
666
+ <span class="cline-any cline-neutral">&nbsp;</span>
667
+ <span class="cline-any cline-no">&nbsp;</span>
668
+ <span class="cline-any cline-no">&nbsp;</span>
669
+ <span class="cline-any cline-no">&nbsp;</span>
670
+ <span class="cline-any cline-no">&nbsp;</span>
671
+ <span class="cline-any cline-no">&nbsp;</span>
672
+ <span class="cline-any cline-no">&nbsp;</span>
673
+ <span class="cline-any cline-neutral">&nbsp;</span>
674
+ <span class="cline-any cline-neutral">&nbsp;</span>
675
+ <span class="cline-any cline-no">&nbsp;</span>
676
+ <span class="cline-any cline-no">&nbsp;</span>
677
+ <span class="cline-any cline-no">&nbsp;</span>
678
+ <span class="cline-any cline-no">&nbsp;</span>
679
+ <span class="cline-any cline-no">&nbsp;</span>
680
+ <span class="cline-any cline-no">&nbsp;</span>
681
+ <span class="cline-any cline-neutral">&nbsp;</span>
682
+ <span class="cline-any cline-no">&nbsp;</span>
683
+ <span class="cline-any cline-no">&nbsp;</span>
684
+ <span class="cline-any cline-no">&nbsp;</span>
685
+ <span class="cline-any cline-neutral">&nbsp;</span>
686
+ <span class="cline-any cline-neutral">&nbsp;</span>
687
+ <span class="cline-any cline-no">&nbsp;</span>
688
+ <span class="cline-any cline-no">&nbsp;</span>
689
+ <span class="cline-any cline-no">&nbsp;</span>
690
+ <span class="cline-any cline-no">&nbsp;</span>
691
+ <span class="cline-any cline-neutral">&nbsp;</span>
692
+ <span class="cline-any cline-neutral">&nbsp;</span>
693
+ <span class="cline-any cline-no">&nbsp;</span>
694
+ <span class="cline-any cline-no">&nbsp;</span>
695
+ <span class="cline-any cline-no">&nbsp;</span>
696
+ <span class="cline-any cline-no">&nbsp;</span>
697
+ <span class="cline-any cline-neutral">&nbsp;</span>
698
+ <span class="cline-any cline-neutral">&nbsp;</span>
699
+ <span class="cline-any cline-no">&nbsp;</span>
700
+ <span class="cline-any cline-no">&nbsp;</span>
701
+ <span class="cline-any cline-no">&nbsp;</span>
702
+ <span class="cline-any cline-no">&nbsp;</span>
703
+ <span class="cline-any cline-no">&nbsp;</span>
704
+ <span class="cline-any cline-no">&nbsp;</span>
705
+ <span class="cline-any cline-no">&nbsp;</span>
706
+ <span class="cline-any cline-no">&nbsp;</span>
707
+ <span class="cline-any cline-neutral">&nbsp;</span>
708
+ <span class="cline-any cline-no">&nbsp;</span>
709
+ <span class="cline-any cline-no">&nbsp;</span>
710
+ <span class="cline-any cline-no">&nbsp;</span>
711
+ <span class="cline-any cline-neutral">&nbsp;</span>
712
+ <span class="cline-any cline-neutral">&nbsp;</span>
713
+ <span class="cline-any cline-no">&nbsp;</span>
714
+ <span class="cline-any cline-no">&nbsp;</span>
715
+ <span class="cline-any cline-no">&nbsp;</span>
716
+ <span class="cline-any cline-no">&nbsp;</span>
717
+ <span class="cline-any cline-neutral">&nbsp;</span>
718
+ <span class="cline-any cline-neutral">&nbsp;</span>
719
+ <span class="cline-any cline-no">&nbsp;</span>
720
+ <span class="cline-any cline-no">&nbsp;</span>
721
+ <span class="cline-any cline-no">&nbsp;</span>
722
+ <span class="cline-any cline-no">&nbsp;</span>
723
+ <span class="cline-any cline-neutral">&nbsp;</span>
724
+ <span class="cline-any cline-neutral">&nbsp;</span>
725
+ <span class="cline-any cline-no">&nbsp;</span>
726
+ <span class="cline-any cline-no">&nbsp;</span>
727
+ <span class="cline-any cline-no">&nbsp;</span>
728
+ <span class="cline-any cline-no">&nbsp;</span>
729
+ <span class="cline-any cline-no">&nbsp;</span>
730
+ <span class="cline-any cline-no">&nbsp;</span>
731
+ <span class="cline-any cline-no">&nbsp;</span>
732
+ <span class="cline-any cline-neutral">&nbsp;</span>
733
+ <span class="cline-any cline-neutral">&nbsp;</span>
734
+ <span class="cline-any cline-no">&nbsp;</span>
735
+ <span class="cline-any cline-no">&nbsp;</span>
736
+ <span class="cline-any cline-no">&nbsp;</span>
737
+ <span class="cline-any cline-no">&nbsp;</span>
738
+ <span class="cline-any cline-no">&nbsp;</span>
739
+ <span class="cline-any cline-no">&nbsp;</span>
740
+ <span class="cline-any cline-no">&nbsp;</span>
741
+ <span class="cline-any cline-no">&nbsp;</span>
742
+ <span class="cline-any cline-no">&nbsp;</span>
743
+ <span class="cline-any cline-no">&nbsp;</span>
744
+ <span class="cline-any cline-no">&nbsp;</span>
745
+ <span class="cline-any cline-no">&nbsp;</span>
746
+ <span class="cline-any cline-no">&nbsp;</span>
747
+ <span class="cline-any cline-no">&nbsp;</span>
748
+ <span class="cline-any cline-neutral">&nbsp;</span>
749
+ <span class="cline-any cline-no">&nbsp;</span>
750
+ <span class="cline-any cline-no">&nbsp;</span>
751
+ <span class="cline-any cline-no">&nbsp;</span>
752
+ <span class="cline-any cline-neutral">&nbsp;</span>
753
+ <span class="cline-any cline-no">&nbsp;</span>
754
+ <span class="cline-any cline-no">&nbsp;</span>
755
+ <span class="cline-any cline-no">&nbsp;</span>
756
+ <span class="cline-any cline-neutral">&nbsp;</span>
757
+ <span class="cline-any cline-neutral">&nbsp;</span>
758
+ <span class="cline-any cline-no">&nbsp;</span>
759
+ <span class="cline-any cline-no">&nbsp;</span>
760
+ <span class="cline-any cline-no">&nbsp;</span>
761
+ <span class="cline-any cline-no">&nbsp;</span>
762
+ <span class="cline-any cline-neutral">&nbsp;</span>
763
+ <span class="cline-any cline-neutral">&nbsp;</span>
764
+ <span class="cline-any cline-no">&nbsp;</span>
765
+ <span class="cline-any cline-no">&nbsp;</span>
766
+ <span class="cline-any cline-no">&nbsp;</span>
767
+ <span class="cline-any cline-no">&nbsp;</span>
768
+ <span class="cline-any cline-neutral">&nbsp;</span>
769
+ <span class="cline-any cline-neutral">&nbsp;</span>
770
+ <span class="cline-any cline-no">&nbsp;</span>
771
+ <span class="cline-any cline-no">&nbsp;</span>
772
+ <span class="cline-any cline-no">&nbsp;</span>
773
+ <span class="cline-any cline-no">&nbsp;</span>
774
+ <span class="cline-any cline-no">&nbsp;</span>
775
+ <span class="cline-any cline-no">&nbsp;</span>
776
+ <span class="cline-any cline-no">&nbsp;</span>
777
+ <span class="cline-any cline-neutral">&nbsp;</span>
778
+ <span class="cline-any cline-neutral">&nbsp;</span>
779
+ <span class="cline-any cline-neutral">&nbsp;</span>
780
+ <span class="cline-any cline-neutral">&nbsp;</span>
781
+ <span class="cline-any cline-no">&nbsp;</span>
782
+ <span class="cline-any cline-no">&nbsp;</span>
783
+ <span class="cline-any cline-no">&nbsp;</span>
784
+ <span class="cline-any cline-no">&nbsp;</span>
785
+ <span class="cline-any cline-no">&nbsp;</span>
786
+ <span class="cline-any cline-no">&nbsp;</span>
787
+ <span class="cline-any cline-no">&nbsp;</span>
788
+ <span class="cline-any cline-no">&nbsp;</span>
789
+ <span class="cline-any cline-no">&nbsp;</span>
790
+ <span class="cline-any cline-no">&nbsp;</span>
791
+ <span class="cline-any cline-no">&nbsp;</span>
792
+ <span class="cline-any cline-no">&nbsp;</span>
793
+ <span class="cline-any cline-neutral">&nbsp;</span>
794
+ <span class="cline-any cline-no">&nbsp;</span>
795
+ <span class="cline-any cline-no">&nbsp;</span>
796
+ <span class="cline-any cline-no">&nbsp;</span>
797
+ <span class="cline-any cline-no">&nbsp;</span>
798
+ <span class="cline-any cline-no">&nbsp;</span>
799
+ <span class="cline-any cline-no">&nbsp;</span>
800
+ <span class="cline-any cline-neutral">&nbsp;</span>
801
+ <span class="cline-any cline-no">&nbsp;</span>
802
+ <span class="cline-any cline-neutral">&nbsp;</span>
803
+ <span class="cline-any cline-no">&nbsp;</span>
804
+ <span class="cline-any cline-neutral">&nbsp;</span>
805
+ <span class="cline-any cline-no">&nbsp;</span>
806
+ <span class="cline-any cline-no">&nbsp;</span>
807
+ <span class="cline-any cline-no">&nbsp;</span>
808
+ <span class="cline-any cline-no">&nbsp;</span>
809
+ <span class="cline-any cline-no">&nbsp;</span>
810
+ <span class="cline-any cline-no">&nbsp;</span>
811
+ <span class="cline-any cline-no">&nbsp;</span>
812
+ <span class="cline-any cline-no">&nbsp;</span>
813
+ <span class="cline-any cline-no">&nbsp;</span>
814
+ <span class="cline-any cline-no">&nbsp;</span>
815
+ <span class="cline-any cline-no">&nbsp;</span>
816
+ <span class="cline-any cline-no">&nbsp;</span>
817
+ <span class="cline-any cline-no">&nbsp;</span>
818
+ <span class="cline-any cline-no">&nbsp;</span>
819
+ <span class="cline-any cline-no">&nbsp;</span>
820
+ <span class="cline-any cline-no">&nbsp;</span>
821
+ <span class="cline-any cline-neutral">&nbsp;</span>
822
+ <span class="cline-any cline-no">&nbsp;</span>
823
+ <span class="cline-any cline-no">&nbsp;</span>
824
+ <span class="cline-any cline-no">&nbsp;</span>
825
+ <span class="cline-any cline-no">&nbsp;</span>
826
+ <span class="cline-any cline-no">&nbsp;</span>
827
+ <span class="cline-any cline-no">&nbsp;</span>
828
+ <span class="cline-any cline-no">&nbsp;</span>
829
+ <span class="cline-any cline-no">&nbsp;</span>
830
+ <span class="cline-any cline-no">&nbsp;</span>
831
+ <span class="cline-any cline-no">&nbsp;</span>
832
+ <span class="cline-any cline-no">&nbsp;</span>
833
+ <span class="cline-any cline-no">&nbsp;</span>
834
+ <span class="cline-any cline-no">&nbsp;</span>
835
+ <span class="cline-any cline-no">&nbsp;</span>
836
+ <span class="cline-any cline-no">&nbsp;</span>
837
+ <span class="cline-any cline-no">&nbsp;</span>
838
+ <span class="cline-any cline-no">&nbsp;</span>
839
+ <span class="cline-any cline-no">&nbsp;</span>
840
+ <span class="cline-any cline-no">&nbsp;</span>
841
+ <span class="cline-any cline-no">&nbsp;</span>
842
+ <span class="cline-any cline-no">&nbsp;</span>
843
+ <span class="cline-any cline-no">&nbsp;</span>
844
+ <span class="cline-any cline-no">&nbsp;</span>
845
+ <span class="cline-any cline-no">&nbsp;</span>
846
+ <span class="cline-any cline-no">&nbsp;</span>
847
+ <span class="cline-any cline-no">&nbsp;</span>
848
+ <span class="cline-any cline-no">&nbsp;</span>
849
+ <span class="cline-any cline-no">&nbsp;</span>
850
+ <span class="cline-any cline-no">&nbsp;</span>
851
+ <span class="cline-any cline-no">&nbsp;</span>
852
+ <span class="cline-any cline-neutral">&nbsp;</span>
853
+ <span class="cline-any cline-no">&nbsp;</span>
854
+ <span class="cline-any cline-no">&nbsp;</span>
855
+ <span class="cline-any cline-no">&nbsp;</span>
856
+ <span class="cline-any cline-no">&nbsp;</span>
857
+ <span class="cline-any cline-no">&nbsp;</span>
858
+ <span class="cline-any cline-no">&nbsp;</span>
859
+ <span class="cline-any cline-no">&nbsp;</span>
860
+ <span class="cline-any cline-no">&nbsp;</span>
861
+ <span class="cline-any cline-no">&nbsp;</span>
862
+ <span class="cline-any cline-no">&nbsp;</span>
863
+ <span class="cline-any cline-no">&nbsp;</span>
864
+ <span class="cline-any cline-no">&nbsp;</span>
865
+ <span class="cline-any cline-no">&nbsp;</span>
866
+ <span class="cline-any cline-no">&nbsp;</span>
867
+ <span class="cline-any cline-no">&nbsp;</span>
868
+ <span class="cline-any cline-no">&nbsp;</span>
869
+ <span class="cline-any cline-no">&nbsp;</span>
870
+ <span class="cline-any cline-no">&nbsp;</span>
871
+ <span class="cline-any cline-no">&nbsp;</span>
872
+ <span class="cline-any cline-neutral">&nbsp;</span>
873
+ <span class="cline-any cline-no">&nbsp;</span>
874
+ <span class="cline-any cline-no">&nbsp;</span>
875
+ <span class="cline-any cline-no">&nbsp;</span>
876
+ <span class="cline-any cline-no">&nbsp;</span>
877
+ <span class="cline-any cline-no">&nbsp;</span>
878
+ <span class="cline-any cline-no">&nbsp;</span>
879
+ <span class="cline-any cline-no">&nbsp;</span>
880
+ <span class="cline-any cline-no">&nbsp;</span>
881
+ <span class="cline-any cline-no">&nbsp;</span>
882
+ <span class="cline-any cline-no">&nbsp;</span>
883
+ <span class="cline-any cline-no">&nbsp;</span>
884
+ <span class="cline-any cline-no">&nbsp;</span>
885
+ <span class="cline-any cline-no">&nbsp;</span>
886
+ <span class="cline-any cline-no">&nbsp;</span>
887
+ <span class="cline-any cline-no">&nbsp;</span>
888
+ <span class="cline-any cline-no">&nbsp;</span>
889
+ <span class="cline-any cline-no">&nbsp;</span>
890
+ <span class="cline-any cline-no">&nbsp;</span>
891
+ <span class="cline-any cline-no">&nbsp;</span>
892
+ <span class="cline-any cline-no">&nbsp;</span>
893
+ <span class="cline-any cline-no">&nbsp;</span>
894
+ <span class="cline-any cline-neutral">&nbsp;</span>
895
+ <span class="cline-any cline-neutral">&nbsp;</span>
896
+ <span class="cline-any cline-neutral">&nbsp;</span>
897
+ <span class="cline-any cline-neutral">&nbsp;</span>
898
+ <span class="cline-any cline-neutral">&nbsp;</span>
899
+ <span class="cline-any cline-no">&nbsp;</span>
900
+ <span class="cline-any cline-neutral">&nbsp;</span>
901
+ <span class="cline-any cline-no">&nbsp;</span>
902
+ <span class="cline-any cline-no">&nbsp;</span>
903
+ <span class="cline-any cline-no">&nbsp;</span>
904
+ <span class="cline-any cline-neutral">&nbsp;</span>
905
+ <span class="cline-any cline-no">&nbsp;</span>
906
+ <span class="cline-any cline-no">&nbsp;</span>
907
+ <span class="cline-any cline-no">&nbsp;</span>
908
+ <span class="cline-any cline-neutral">&nbsp;</span>
909
+ <span class="cline-any cline-no">&nbsp;</span>
910
+ <span class="cline-any cline-no">&nbsp;</span>
911
+ <span class="cline-any cline-no">&nbsp;</span>
912
+ <span class="cline-any cline-no">&nbsp;</span>
913
+ <span class="cline-any cline-neutral">&nbsp;</span>
914
+ <span class="cline-any cline-no">&nbsp;</span>
915
+ <span class="cline-any cline-no">&nbsp;</span>
916
+ <span class="cline-any cline-no">&nbsp;</span>
917
+ <span class="cline-any cline-no">&nbsp;</span>
918
+ <span class="cline-any cline-no">&nbsp;</span>
919
+ <span class="cline-any cline-no">&nbsp;</span>
920
+ <span class="cline-any cline-no">&nbsp;</span>
921
+ <span class="cline-any cline-neutral">&nbsp;</span>
922
+ <span class="cline-any cline-no">&nbsp;</span>
923
+ <span class="cline-any cline-no">&nbsp;</span>
924
+ <span class="cline-any cline-no">&nbsp;</span>
925
+ <span class="cline-any cline-no">&nbsp;</span>
926
+ <span class="cline-any cline-no">&nbsp;</span>
927
+ <span class="cline-any cline-no">&nbsp;</span>
928
+ <span class="cline-any cline-no">&nbsp;</span>
929
+ <span class="cline-any cline-no">&nbsp;</span>
930
+ <span class="cline-any cline-no">&nbsp;</span>
931
+ <span class="cline-any cline-no">&nbsp;</span>
932
+ <span class="cline-any cline-no">&nbsp;</span>
933
+ <span class="cline-any cline-no">&nbsp;</span>
934
+ <span class="cline-any cline-no">&nbsp;</span>
935
+ <span class="cline-any cline-neutral">&nbsp;</span>
936
+ <span class="cline-any cline-no">&nbsp;</span>
937
+ <span class="cline-any cline-no">&nbsp;</span>
938
+ <span class="cline-any cline-no">&nbsp;</span>
939
+ <span class="cline-any cline-no">&nbsp;</span>
940
+ <span class="cline-any cline-no">&nbsp;</span>
941
+ <span class="cline-any cline-no">&nbsp;</span>
942
+ <span class="cline-any cline-no">&nbsp;</span>
943
+ <span class="cline-any cline-no">&nbsp;</span>
944
+ <span class="cline-any cline-no">&nbsp;</span>
945
+ <span class="cline-any cline-no">&nbsp;</span>
946
+ <span class="cline-any cline-no">&nbsp;</span>
947
+ <span class="cline-any cline-no">&nbsp;</span>
948
+ <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">/* Copyright(C) 2021-2024, donavanbecker (https://github.com/donavanbecker). All rights reserved.
949
+ *
950
+ * hub.ts: @switchbot/homebridge-switchbot.
951
+ */
952
+ import type { CharacteristicValue, PlatformAccessory, Service } from 'homebridge'
953
+ import type { device, hub2ServiceData, hub2Status, hub2WebhookContext, SwitchBotBLE } from 'node-switchbot'
954
+ &nbsp;
955
+ import type { SwitchBotPlatform } from '../platform.js'
956
+ import type { devicesConfig, hubConfig } from '../settings.js'
957
+ &nbsp;
958
+ import { Units } from 'homebridge'
959
+ /*
960
+ * For Testing Locally:
961
+ * import { SwitchBotBLEModel, SwitchBotBLEModelName } from '/Users/Shared/GitHub/OpenWonderLabs/node-switchbot/dist/index.js';
962
+ */
963
+ import { SwitchBotBLEModel, SwitchBotBLEModelName } from 'node-switchbot'
964
+ import { interval, skipWhile, Subject } from 'rxjs'
965
+ &nbsp;
966
+ import { convertUnits, formatDeviceIdAsMac, validHumidity } from '../utils.js'
967
+ import { deviceBase } from './device.js'
968
+ &nbsp;
969
+ export <span class="fstat-no" title="function not covered" ><span class="branch-0 cbranch-no" title="branch not covered" >class Hub extends deviceBase {</span></span>
970
+ // Services
971
+ <span class="cstat-no" title="statement not covered" > private LightSensor?: {</span>
972
+ Name: CharacteristicValue
973
+ Service: Service
974
+ CurrentAmbientLightLevel: CharacteristicValue
975
+ }
976
+ &nbsp;
977
+ <span class="cstat-no" title="statement not covered" > private HumiditySensor?: {</span>
978
+ Name: CharacteristicValue
979
+ Service: Service
980
+ CurrentRelativeHumidity: CharacteristicValue
981
+ }
982
+ &nbsp;
983
+ <span class="cstat-no" title="statement not covered" > private TemperatureSensor?: {</span>
984
+ Name: CharacteristicValue
985
+ Service: Service
986
+ CurrentTemperature: CharacteristicValue
987
+ }
988
+ &nbsp;
989
+ // OpenAPI
990
+ <span class="cstat-no" title="statement not covered" > deviceStatus!: hub2Status</span>
991
+ &nbsp;
992
+ // Webhook
993
+ <span class="cstat-no" title="statement not covered" > webhookContext!: hub2WebhookContext</span>
994
+ &nbsp;
995
+ // BLE
996
+ <span class="cstat-no" title="statement not covered" > serviceData!: hub2ServiceData</span>
997
+ &nbsp;
998
+ // Updates
999
+ <span class="cstat-no" title="statement not covered" > hubUpdateInProgress!: boolean</span>
1000
+ <span class="cstat-no" title="statement not covered" > doHubUpdate!: Subject&lt;void&gt;</span>
1001
+ &nbsp;
1002
+ <span class="cstat-no" title="statement not covered" > constructor(</span>
1003
+ <span class="cstat-no" title="statement not covered" > readonly platform: SwitchBotPlatform,</span>
1004
+ <span class="cstat-no" title="statement not covered" > accessory: PlatformAccessory,</span>
1005
+ <span class="cstat-no" title="statement not covered" > device: device &amp; devicesConfig,</span>
1006
+ <span class="cstat-no" title="statement not covered" > ) {</span>
1007
+ <span class="cstat-no" title="statement not covered" > super(platform, accessory, device)</span>
1008
+ // Set category
1009
+ <span class="cstat-no" title="statement not covered" > accessory.category = this.hap.Categories.SENSOR</span>
1010
+ &nbsp;
1011
+ // this is subject we use to track when we need to POST changes to the SwitchBot API
1012
+ <span class="cstat-no" title="statement not covered" > this.doHubUpdate = new Subject()</span>
1013
+ <span class="cstat-no" title="statement not covered" > this.hubUpdateInProgress = false</span>
1014
+ &nbsp;
1015
+ // Initialize Temperature Sensor Service
1016
+ <span class="cstat-no" title="statement not covered" > if ((device as hubConfig).hide_temperature) {</span>
1017
+ <span class="cstat-no" title="statement not covered" > if (this.TemperatureSensor) {</span>
1018
+ <span class="cstat-no" title="statement not covered" > this.debugLog('Removing Temperature Sensor Service')</span>
1019
+ <span class="cstat-no" title="statement not covered" > this.TemperatureSensor.Service = this.accessory.getService(this.hap.Service.TemperatureSensor) as Service</span>
1020
+ <span class="cstat-no" title="statement not covered" > accessory.removeService(this.TemperatureSensor.Service)</span>
1021
+ <span class="cstat-no" title="statement not covered" > }</span>
1022
+ <span class="cstat-no" title="statement not covered" > } else {</span>
1023
+ <span class="cstat-no" title="statement not covered" > accessory.context.TemperatureSensor = accessory.context.TemperatureSensor ?? {}</span>
1024
+ <span class="cstat-no" title="statement not covered" > this.TemperatureSensor = {</span>
1025
+ <span class="cstat-no" title="statement not covered" > Name: `${accessory.displayName} Temperature Sensor`,</span>
1026
+ <span class="cstat-no" title="statement not covered" > Service: accessory.getService(this.hap.Service.TemperatureSensor) ?? this.accessory.addService(this.hap.Service.TemperatureSensor) as Service,</span>
1027
+ <span class="cstat-no" title="statement not covered" > CurrentTemperature: accessory.context.CurrentTemperature ?? 0,</span>
1028
+ <span class="cstat-no" title="statement not covered" > }</span>
1029
+ <span class="cstat-no" title="statement not covered" > accessory.context.TemperatureSensor = this.TemperatureSensor as object</span>
1030
+ &nbsp;
1031
+ // Initialize Temperature Sensor Characteristic
1032
+ <span class="cstat-no" title="statement not covered" > this.TemperatureSensor.Service.setCharacteristic(this.hap.Characteristic.Name, this.TemperatureSensor.Name).getCharacteristic(this.hap.Characteristic.CurrentTemperature).setProps({</span>
1033
+ <span class="cstat-no" title="statement not covered" > unit: Units.CELSIUS,</span>
1034
+ <span class="cstat-no" title="statement not covered" > validValueRanges: [-273.15, 100],</span>
1035
+ <span class="cstat-no" title="statement not covered" > minValue: -273.15,</span>
1036
+ <span class="cstat-no" title="statement not covered" > maxValue: 100,</span>
1037
+ <span class="cstat-no" title="statement not covered" > minStep: 0.1,</span>
1038
+ <span class="cstat-no" title="statement not covered" > }).onGet(() =&gt; {</span>
1039
+ <span class="cstat-no" title="statement not covered" > return this.TemperatureSensor!.CurrentTemperature</span>
1040
+ <span class="cstat-no" title="statement not covered" > })</span>
1041
+ <span class="cstat-no" title="statement not covered" > }</span>
1042
+ &nbsp;
1043
+ // Initialize Humidity Sensor Service
1044
+ <span class="cstat-no" title="statement not covered" > if ((device as hubConfig).hide_humidity) {</span>
1045
+ <span class="cstat-no" title="statement not covered" > if (this.HumiditySensor) {</span>
1046
+ <span class="cstat-no" title="statement not covered" > this.debugLog('Removing Humidity Sensor Service')</span>
1047
+ <span class="cstat-no" title="statement not covered" > this.HumiditySensor.Service = this.accessory.getService(this.hap.Service.HumiditySensor) as Service</span>
1048
+ <span class="cstat-no" title="statement not covered" > accessory.removeService(this.HumiditySensor.Service)</span>
1049
+ <span class="cstat-no" title="statement not covered" > }</span>
1050
+ <span class="cstat-no" title="statement not covered" > } else {</span>
1051
+ <span class="cstat-no" title="statement not covered" > accessory.context.HumiditySensor = accessory.context.HumiditySensor ?? {}</span>
1052
+ <span class="cstat-no" title="statement not covered" > this.HumiditySensor = {</span>
1053
+ <span class="cstat-no" title="statement not covered" > Name: `${accessory.displayName} Humidity Sensor`,</span>
1054
+ <span class="cstat-no" title="statement not covered" > Service: accessory.getService(this.hap.Service.HumiditySensor) ?? this.accessory.addService(this.hap.Service.HumiditySensor) as Service,</span>
1055
+ <span class="cstat-no" title="statement not covered" > CurrentRelativeHumidity: accessory.context.CurrentRelativeHumidity ?? 0,</span>
1056
+ <span class="cstat-no" title="statement not covered" > }</span>
1057
+ <span class="cstat-no" title="statement not covered" > accessory.context.HumiditySensor = this.HumiditySensor as object</span>
1058
+ &nbsp;
1059
+ // Initialize Humidity Sensor Characteristics
1060
+ <span class="cstat-no" title="statement not covered" > this.HumiditySensor!.Service.setCharacteristic(this.hap.Characteristic.Name, this.HumiditySensor.Name).getCharacteristic(this.hap.Characteristic.CurrentRelativeHumidity).setProps({</span>
1061
+ <span class="cstat-no" title="statement not covered" > minStep: 0.1,</span>
1062
+ <span class="cstat-no" title="statement not covered" > }).onGet(() =&gt; {</span>
1063
+ <span class="cstat-no" title="statement not covered" > return this.HumiditySensor!.CurrentRelativeHumidity</span>
1064
+ <span class="cstat-no" title="statement not covered" > })</span>
1065
+ <span class="cstat-no" title="statement not covered" > }</span>
1066
+ &nbsp;
1067
+ // Initialize Light Sensor Service
1068
+ <span class="cstat-no" title="statement not covered" > if ((device as hubConfig).hide_lightsensor) {</span>
1069
+ <span class="cstat-no" title="statement not covered" > if (this.LightSensor) {</span>
1070
+ <span class="cstat-no" title="statement not covered" > this.debugLog('Removing Light Sensor Service')</span>
1071
+ <span class="cstat-no" title="statement not covered" > this.LightSensor.Service = this.accessory.getService(this.hap.Service.LightSensor) as Service</span>
1072
+ <span class="cstat-no" title="statement not covered" > accessory.removeService(this.LightSensor.Service)</span>
1073
+ <span class="cstat-no" title="statement not covered" > }</span>
1074
+ <span class="cstat-no" title="statement not covered" > } else {</span>
1075
+ <span class="cstat-no" title="statement not covered" > accessory.context.LightSensor = accessory.context.LightSensor ?? {}</span>
1076
+ <span class="cstat-no" title="statement not covered" > this.LightSensor = {</span>
1077
+ <span class="cstat-no" title="statement not covered" > Name: `${accessory.displayName} Light Sensor`,</span>
1078
+ <span class="cstat-no" title="statement not covered" > Service: accessory.getService(this.hap.Service.LightSensor) ?? this.accessory.addService(this.hap.Service.LightSensor) as Service,</span>
1079
+ <span class="cstat-no" title="statement not covered" > CurrentAmbientLightLevel: accessory.context.CurrentAmbientLightLevel ?? 0.0001,</span>
1080
+ <span class="cstat-no" title="statement not covered" > }</span>
1081
+ <span class="cstat-no" title="statement not covered" > accessory.context.LightSensor = this.LightSensor as object</span>
1082
+ &nbsp;
1083
+ // Initialize Light Sensor Characteristics
1084
+ <span class="cstat-no" title="statement not covered" > this.LightSensor!.Service.setCharacteristic(this.hap.Characteristic.Name, this.LightSensor.Name).getCharacteristic(this.hap.Characteristic.CurrentAmbientLightLevel).setProps({</span>
1085
+ <span class="cstat-no" title="statement not covered" > minStep: 1,</span>
1086
+ <span class="cstat-no" title="statement not covered" > }).onGet(() =&gt; {</span>
1087
+ <span class="cstat-no" title="statement not covered" > return this.LightSensor!.CurrentAmbientLightLevel</span>
1088
+ <span class="cstat-no" title="statement not covered" > })</span>
1089
+ <span class="cstat-no" title="statement not covered" > }</span>
1090
+ &nbsp;
1091
+ // Retrieve initial values and updateHomekit
1092
+ <span class="cstat-no" title="statement not covered" > try {</span>
1093
+ <span class="cstat-no" title="statement not covered" > this.debugLog('Retrieve initial values and update Homekit')</span>
1094
+ <span class="cstat-no" title="statement not covered" > this.refreshStatus()</span>
1095
+ <span class="cstat-no" title="statement not covered" > } catch (e: any) {</span>
1096
+ <span class="cstat-no" title="statement not covered" > this.errorLog(`failed to retrieve initial values and update Homekit, Error: ${e.message ?? e}`)</span>
1097
+ <span class="cstat-no" title="statement not covered" > }</span>
1098
+ &nbsp;
1099
+ // regisiter webhook event handler if enabled
1100
+ <span class="cstat-no" title="statement not covered" > try {</span>
1101
+ <span class="cstat-no" title="statement not covered" > this.debugLog('Registering Webhook Event Handler')</span>
1102
+ <span class="cstat-no" title="statement not covered" > this.registerWebhook()</span>
1103
+ <span class="cstat-no" title="statement not covered" > } catch (e: any) {</span>
1104
+ <span class="cstat-no" title="statement not covered" > this.errorLog(`failed to registerWebhook, Error: ${e.message ?? e}`)</span>
1105
+ <span class="cstat-no" title="statement not covered" > }</span>
1106
+ &nbsp;
1107
+ // regisiter platform BLE event handler if enabled
1108
+ <span class="cstat-no" title="statement not covered" > try {</span>
1109
+ <span class="cstat-no" title="statement not covered" > this.debugLog('Registering Platform BLE Event Handler')</span>
1110
+ <span class="cstat-no" title="statement not covered" > this.registerPlatformBLE()</span>
1111
+ <span class="cstat-no" title="statement not covered" > } catch (e: any) {</span>
1112
+ <span class="cstat-no" title="statement not covered" > this.errorLog(`failed to registerPlatformBLE, Error: ${e.message ?? e}`)</span>
1113
+ <span class="cstat-no" title="statement not covered" > }</span>
1114
+ &nbsp;
1115
+ // Start an update interval
1116
+ <span class="cstat-no" title="statement not covered" > interval(this.deviceRefreshRate * 1000)</span>
1117
+ <span class="cstat-no" title="statement not covered" > .pipe(skipWhile(() =&gt; this.hubUpdateInProgress))</span>
1118
+ <span class="cstat-no" title="statement not covered" > .subscribe(async () =&gt; {</span>
1119
+ <span class="cstat-no" title="statement not covered" > await this.refreshStatus()</span>
1120
+ <span class="cstat-no" title="statement not covered" > })</span>
1121
+ <span class="cstat-no" title="statement not covered" > }</span>
1122
+ &nbsp;
1123
+ <span class="cstat-no" title="statement not covered" > async BLEparseStatus(): Promise&lt;void&gt; {</span>
1124
+ <span class="cstat-no" title="statement not covered" > this.debugLog('BLEparseStatus')</span>
1125
+ <span class="cstat-no" title="statement not covered" > this.debugLog(`(temperature, humidity, lightLevel) = BLE:(${this.serviceData.celsius}, ${this.serviceData.humidity}, ${this.serviceData.lightLevel}), current:(${this.TemperatureSensor?.CurrentTemperature}, ${this.HumiditySensor?.CurrentRelativeHumidity}, ${this.LightSensor?.CurrentAmbientLightLevel})`)</span>
1126
+ &nbsp;
1127
+ // CurrentTemperature
1128
+ <span class="cstat-no" title="statement not covered" > if (!(this.device as hubConfig).hide_temperature &amp;&amp; this.TemperatureSensor?.Service) {</span>
1129
+ <span class="cstat-no" title="statement not covered" > this.TemperatureSensor.CurrentTemperature = this.serviceData.celsius</span>
1130
+ <span class="cstat-no" title="statement not covered" > this.debugLog(`CurrentTemperature: ${this.TemperatureSensor.CurrentTemperature}°c`)</span>
1131
+ <span class="cstat-no" title="statement not covered" > }</span>
1132
+ &nbsp;
1133
+ // CurrentRelativeHumidity
1134
+ <span class="cstat-no" title="statement not covered" > if (!(this.device as hubConfig).hide_humidity &amp;&amp; this.HumiditySensor?.Service) {</span>
1135
+ <span class="cstat-no" title="statement not covered" > this.HumiditySensor!.CurrentRelativeHumidity = validHumidity(this.serviceData.humidity, 0, 100)</span>
1136
+ <span class="cstat-no" title="statement not covered" > this.debugLog(`CurrentRelativeHumidity: ${this.HumiditySensor.CurrentRelativeHumidity}%`)</span>
1137
+ <span class="cstat-no" title="statement not covered" > }</span>
1138
+ &nbsp;
1139
+ // CurrentAmbientLightLevel
1140
+ <span class="cstat-no" title="statement not covered" > if (!(this.device as hubConfig).hide_lightsensor &amp;&amp; this.LightSensor?.Service) {</span>
1141
+ <span class="cstat-no" title="statement not covered" > const set_minLux = (this.device as hubConfig).set_minLux ?? 1</span>
1142
+ <span class="cstat-no" title="statement not covered" > const set_maxLux = (this.device as hubConfig).set_maxLux ?? 6001</span>
1143
+ <span class="cstat-no" title="statement not covered" > const lightLevel = this.serviceData.lightLevel</span>
1144
+ <span class="cstat-no" title="statement not covered" > this.LightSensor.CurrentAmbientLightLevel = this.getLightLevel(lightLevel, set_minLux, set_maxLux, 19)</span>
1145
+ <span class="cstat-no" title="statement not covered" > this.debugLog(`LightLevel: ${this.serviceData.lightLevel}, CurrentAmbientLightLevel: ${this.LightSensor.CurrentAmbientLightLevel}`)</span>
1146
+ <span class="cstat-no" title="statement not covered" > }</span>
1147
+ <span class="cstat-no" title="statement not covered" > }</span>
1148
+ &nbsp;
1149
+ <span class="cstat-no" title="statement not covered" > async openAPIparseStatus(): Promise&lt;void&gt; {</span>
1150
+ <span class="cstat-no" title="statement not covered" > this.debugLog('openAPIparseStatus')</span>
1151
+ <span class="cstat-no" title="statement not covered" > this.debugLog(`(temperature, humidity, lightLevel) = OpenAPI:(${this.deviceStatus.temperature}, ${this.deviceStatus.humidity}, ${this.deviceStatus.lightLevel}), current:(${this.TemperatureSensor?.CurrentTemperature}, ${this.HumiditySensor?.CurrentRelativeHumidity}, ${this.LightSensor?.CurrentAmbientLightLevel})`)</span>
1152
+ &nbsp;
1153
+ // CurrentRelativeHumidity
1154
+ <span class="cstat-no" title="statement not covered" > if (!(this.device as hubConfig).hide_humidity &amp;&amp; this.HumiditySensor?.Service) {</span>
1155
+ <span class="cstat-no" title="statement not covered" > this.HumiditySensor.CurrentRelativeHumidity = this.deviceStatus.humidity</span>
1156
+ <span class="cstat-no" title="statement not covered" > this.debugLog(`CurrentRelativeHumidity: ${this.HumiditySensor.CurrentRelativeHumidity}%`)</span>
1157
+ <span class="cstat-no" title="statement not covered" > }</span>
1158
+ &nbsp;
1159
+ // CurrentTemperature
1160
+ <span class="cstat-no" title="statement not covered" > if (!(this.device as hubConfig).hide_temperature &amp;&amp; this.TemperatureSensor?.Service) {</span>
1161
+ <span class="cstat-no" title="statement not covered" > this.TemperatureSensor.CurrentTemperature = this.deviceStatus.temperature</span>
1162
+ <span class="cstat-no" title="statement not covered" > this.debugLog(`CurrentTemperature: ${this.TemperatureSensor.CurrentTemperature}°c`)</span>
1163
+ <span class="cstat-no" title="statement not covered" > }</span>
1164
+ &nbsp;
1165
+ // LightSensor
1166
+ <span class="cstat-no" title="statement not covered" > if (!(this.device as hubConfig).hide_lightsensor &amp;&amp; this.LightSensor?.Service) {</span>
1167
+ <span class="cstat-no" title="statement not covered" > const set_minLux = (this.device as hubConfig).set_minLux ?? 1</span>
1168
+ <span class="cstat-no" title="statement not covered" > const set_maxLux = (this.device as hubConfig).set_maxLux ?? 6001</span>
1169
+ <span class="cstat-no" title="statement not covered" > const lightLevel = this.deviceStatus.lightLevel</span>
1170
+ <span class="cstat-no" title="statement not covered" > this.LightSensor.CurrentAmbientLightLevel = this.getLightLevel(lightLevel, set_minLux, set_maxLux, 19)</span>
1171
+ <span class="cstat-no" title="statement not covered" > this.debugLog(`LightLevel: ${this.deviceStatus.lightLevel}, CurrentAmbientLightLevel: ${this.LightSensor!.CurrentAmbientLightLevel}`)</span>
1172
+ <span class="cstat-no" title="statement not covered" > }</span>
1173
+ &nbsp;
1174
+ // Firmware Version
1175
+ <span class="cstat-no" title="statement not covered" > if (this.deviceStatus.version) {</span>
1176
+ <span class="cstat-no" title="statement not covered" > const version = this.deviceStatus.version.toString()</span>
1177
+ <span class="cstat-no" title="statement not covered" > this.debugLog(`Firmware Version: ${version.replace(/^V|-.*$/g, '')}`)</span>
1178
+ <span class="cstat-no" title="statement not covered" > const deviceVersion = version.replace(/^V|-.*$/g, '') ?? '0.0.0'</span>
1179
+ <span class="cstat-no" title="statement not covered" > this.accessory</span>
1180
+ <span class="cstat-no" title="statement not covered" > .getService(this.hap.Service.AccessoryInformation)!</span>
1181
+ <span class="cstat-no" title="statement not covered" > .setCharacteristic(this.hap.Characteristic.HardwareRevision, deviceVersion)</span>
1182
+ <span class="cstat-no" title="statement not covered" > .setCharacteristic(this.hap.Characteristic.FirmwareRevision, deviceVersion)</span>
1183
+ <span class="cstat-no" title="statement not covered" > .getCharacteristic(this.hap.Characteristic.FirmwareRevision)</span>
1184
+ <span class="cstat-no" title="statement not covered" > .updateValue(deviceVersion)</span>
1185
+ <span class="cstat-no" title="statement not covered" > this.accessory.context.version = deviceVersion</span>
1186
+ <span class="cstat-no" title="statement not covered" > this.debugSuccessLog(`version: ${this.accessory.context.version}`)</span>
1187
+ <span class="cstat-no" title="statement not covered" > }</span>
1188
+ <span class="cstat-no" title="statement not covered" > }</span>
1189
+ &nbsp;
1190
+ <span class="cstat-no" title="statement not covered" > async parseStatusWebhook(): Promise&lt;void&gt; {</span>
1191
+ <span class="cstat-no" title="statement not covered" > this.debugLog('parseStatusWebhook')</span>
1192
+ <span class="cstat-no" title="statement not covered" > this.debugLog(`(scale, temperature, humidity, lightLevel) = Webhook:(${this.webhookContext.scale}, ${convertUnits(this.webhookContext.temperature, this.webhookContext.scale, (this.device as hubConfig).convertUnitTo)}, ${this.webhookContext.humidity}, ${this.webhookContext.lightLevel}), current:(${this.TemperatureSensor?.CurrentTemperature}, ${this.HumiditySensor?.CurrentRelativeHumidity}, ${this.LightSensor?.CurrentAmbientLightLevel})`)</span>
1193
+ // Check if the scale is not CELSIUS
1194
+ <span class="cstat-no" title="statement not covered" > if (this.webhookContext.scale !== 'CELSIUS' &amp;&amp; (this.device as hubConfig).convertUnitTo === undefined) {</span>
1195
+ <span class="cstat-no" title="statement not covered" > this.warnLog(`received a non-CELSIUS Webhook scale: ${this.webhookContext.scale}, Use the *convertUnitsTo* config under Hub settings, if displaying incorrectly in HomeKit.`)</span>
1196
+ <span class="cstat-no" title="statement not covered" > }</span>
1197
+ &nbsp;
1198
+ // CurrentRelativeHumidity
1199
+ <span class="cstat-no" title="statement not covered" > if (!(this.device as hubConfig).hide_humidity &amp;&amp; this.HumiditySensor?.Service) {</span>
1200
+ <span class="cstat-no" title="statement not covered" > this.HumiditySensor.CurrentRelativeHumidity = this.webhookContext.humidity</span>
1201
+ <span class="cstat-no" title="statement not covered" > this.debugLog(`CurrentRelativeHumidity: ${this.HumiditySensor.CurrentRelativeHumidity}`)</span>
1202
+ <span class="cstat-no" title="statement not covered" > }</span>
1203
+ &nbsp;
1204
+ // CurrentTemperature
1205
+ <span class="cstat-no" title="statement not covered" > if (!(this.device as hubConfig).hide_temperature &amp;&amp; this.TemperatureSensor?.Service) {</span>
1206
+ <span class="cstat-no" title="statement not covered" > this.TemperatureSensor.CurrentTemperature = convertUnits(this.webhookContext.temperature, this.webhookContext.scale, (this.device as hubConfig).convertUnitTo)</span>
1207
+ <span class="cstat-no" title="statement not covered" > this.debugLog(`CurrentTemperature: ${this.TemperatureSensor.CurrentTemperature}`)</span>
1208
+ <span class="cstat-no" title="statement not covered" > }</span>
1209
+ &nbsp;
1210
+ // CurrentAmbientLightLevel
1211
+ <span class="cstat-no" title="statement not covered" > if (!(this.device as hubConfig).hide_lightsensor &amp;&amp; this.LightSensor?.Service) {</span>
1212
+ <span class="cstat-no" title="statement not covered" > const set_minLux = (this.device as hubConfig).set_minLux ?? 1</span>
1213
+ <span class="cstat-no" title="statement not covered" > const set_maxLux = (this.device as hubConfig).set_maxLux ?? 6001</span>
1214
+ <span class="cstat-no" title="statement not covered" > this.LightSensor.CurrentAmbientLightLevel = this.getLightLevel(this.webhookContext.lightLevel, set_minLux, set_maxLux, 19)</span>
1215
+ <span class="cstat-no" title="statement not covered" > this.debugLog(`CurrentAmbientLightLevel: ${this.LightSensor.CurrentAmbientLightLevel}`)</span>
1216
+ <span class="cstat-no" title="statement not covered" > }</span>
1217
+ <span class="cstat-no" title="statement not covered" > }</span>
1218
+ &nbsp;
1219
+ /**
1220
+ * Asks the SwitchBot API for the latest device information
1221
+ */
1222
+ <span class="cstat-no" title="statement not covered" > async refreshStatus(): Promise&lt;void&gt; {</span>
1223
+ <span class="cstat-no" title="statement not covered" > if (!this.device.enableCloudService &amp;&amp; this.OpenAPI) {</span>
1224
+ <span class="cstat-no" title="statement not covered" > this.errorLog(`refreshStatus enableCloudService: ${this.device.enableCloudService}`)</span>
1225
+ <span class="cstat-no" title="statement not covered" > } else if (this.BLE) {</span>
1226
+ <span class="cstat-no" title="statement not covered" > await this.BLERefreshStatus()</span>
1227
+ <span class="cstat-no" title="statement not covered" > } else if (this.OpenAPI &amp;&amp; this.platform.config.credentials?.token) {</span>
1228
+ <span class="cstat-no" title="statement not covered" > await this.openAPIRefreshStatus()</span>
1229
+ <span class="cstat-no" title="statement not covered" > } else {</span>
1230
+ <span class="cstat-no" title="statement not covered" > await this.offlineOff()</span>
1231
+ <span class="cstat-no" title="statement not covered" > this.debugWarnLog(`Connection Type: ${this.device.connectionType}, refreshStatus will not happen.`)</span>
1232
+ <span class="cstat-no" title="statement not covered" > }</span>
1233
+ <span class="cstat-no" title="statement not covered" > }</span>
1234
+ &nbsp;
1235
+ <span class="cstat-no" title="statement not covered" > async BLERefreshStatus(): Promise&lt;void&gt; {</span>
1236
+ <span class="cstat-no" title="statement not covered" > this.debugLog('BLERefreshStatus')</span>
1237
+ <span class="cstat-no" title="statement not covered" > const switchBotBLE = await this.switchbotBLE()</span>
1238
+ <span class="cstat-no" title="statement not covered" > if (switchBotBLE === undefined) {</span>
1239
+ <span class="cstat-no" title="statement not covered" > await this.BLERefreshConnection(switchBotBLE)</span>
1240
+ <span class="cstat-no" title="statement not covered" > } else {</span>
1241
+ // Start to monitor advertisement packets
1242
+ <span class="cstat-no" title="statement not covered" > (async () =&gt; {</span>
1243
+ // Start to monitor advertisement packets
1244
+ <span class="cstat-no" title="statement not covered" > const serviceData = await this.monitorAdvertisementPackets(switchBotBLE) as hub2ServiceData</span>
1245
+ // Update HomeKit
1246
+ <span class="cstat-no" title="statement not covered" > if (serviceData.model === SwitchBotBLEModel.Hub2 &amp;&amp; serviceData.modelName === SwitchBotBLEModelName.Hub2) {</span>
1247
+ <span class="cstat-no" title="statement not covered" > this.serviceData = serviceData</span>
1248
+ <span class="cstat-no" title="statement not covered" > if (serviceData !== undefined || serviceData !== null) {</span>
1249
+ <span class="cstat-no" title="statement not covered" > await this.BLEparseStatus()</span>
1250
+ <span class="cstat-no" title="statement not covered" > await this.updateHomeKitCharacteristics()</span>
1251
+ <span class="cstat-no" title="statement not covered" > } else {</span>
1252
+ <span class="cstat-no" title="statement not covered" > this.errorLog(`serviceData is either undefined or null, serviceData: ${JSON.stringify(serviceData)}`)</span>
1253
+ <span class="cstat-no" title="statement not covered" > await this.BLERefreshConnection(switchBotBLE)</span>
1254
+ <span class="cstat-no" title="statement not covered" > }</span>
1255
+ <span class="cstat-no" title="statement not covered" > } else {</span>
1256
+ <span class="cstat-no" title="statement not covered" > this.errorLog(`failed to get serviceData, serviceData: ${JSON.stringify(serviceData)}`)</span>
1257
+ <span class="cstat-no" title="statement not covered" > await this.BLERefreshConnection(switchBotBLE)</span>
1258
+ <span class="cstat-no" title="statement not covered" > }</span>
1259
+ <span class="cstat-no" title="statement not covered" > })()</span>
1260
+ <span class="cstat-no" title="statement not covered" > }</span>
1261
+ <span class="cstat-no" title="statement not covered" > }</span>
1262
+ &nbsp;
1263
+ <span class="cstat-no" title="statement not covered" > async registerPlatformBLE(): Promise&lt;void&gt; {</span>
1264
+ <span class="cstat-no" title="statement not covered" > this.debugLog('registerPlatformBLE')</span>
1265
+ <span class="cstat-no" title="statement not covered" > if (this.config.options?.BLE &amp;&amp; !this.device.disablePlatformBLE) {</span>
1266
+ <span class="cstat-no" title="statement not covered" > this.debugLog('is listening to Platform BLE.')</span>
1267
+ <span class="cstat-no" title="statement not covered" > try {</span>
1268
+ <span class="cstat-no" title="statement not covered" > const formattedDeviceId = formatDeviceIdAsMac(this.device.deviceId)</span>
1269
+ <span class="cstat-no" title="statement not covered" > this.device.bleMac = formattedDeviceId</span>
1270
+ <span class="cstat-no" title="statement not covered" > this.debugLog(`bleMac: ${this.device.bleMac}`)</span>
1271
+ <span class="cstat-no" title="statement not covered" > this.platform.bleEventHandler[this.device.bleMac] = async (context: hub2ServiceData) =&gt; {</span>
1272
+ <span class="cstat-no" title="statement not covered" > try {</span>
1273
+ <span class="cstat-no" title="statement not covered" > this.serviceData = context</span>
1274
+ <span class="cstat-no" title="statement not covered" > if (context !== undefined || context !== null) {</span>
1275
+ <span class="cstat-no" title="statement not covered" > this.debugLog(`received BLE: ${JSON.stringify(context)}`)</span>
1276
+ <span class="cstat-no" title="statement not covered" > await this.BLEparseStatus()</span>
1277
+ <span class="cstat-no" title="statement not covered" > await this.updateHomeKitCharacteristics()</span>
1278
+ <span class="cstat-no" title="statement not covered" > } else {</span>
1279
+ <span class="cstat-no" title="statement not covered" > this.errorLog(`context is either undefined or null, context: ${JSON.stringify(context)}`)</span>
1280
+ <span class="cstat-no" title="statement not covered" > await this.BLERefreshConnection(context)</span>
1281
+ <span class="cstat-no" title="statement not covered" > }</span>
1282
+ <span class="cstat-no" title="statement not covered" > } catch (e: any) {</span>
1283
+ <span class="cstat-no" title="statement not covered" > this.errorLog(`failed to handle BLE. Received: ${JSON.stringify(context)} Error: ${e.message ?? e}`)</span>
1284
+ <span class="cstat-no" title="statement not covered" > }</span>
1285
+ <span class="cstat-no" title="statement not covered" > }</span>
1286
+ <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
1287
+ <span class="cstat-no" title="statement not covered" > this.errorLog(`failed to format device ID as MAC, Error: ${error}`)</span>
1288
+ <span class="cstat-no" title="statement not covered" > }</span>
1289
+ <span class="cstat-no" title="statement not covered" > } else {</span>
1290
+ <span class="cstat-no" title="statement not covered" > this.debugLog('is not listening to Platform BLE')</span>
1291
+ <span class="cstat-no" title="statement not covered" > }</span>
1292
+ <span class="cstat-no" title="statement not covered" > }</span>
1293
+ &nbsp;
1294
+ <span class="cstat-no" title="statement not covered" > async openAPIRefreshStatus(): Promise&lt;void&gt; {</span>
1295
+ <span class="cstat-no" title="statement not covered" > this.debugLog('openAPIRefreshStatus')</span>
1296
+ <span class="cstat-no" title="statement not covered" > try {</span>
1297
+ <span class="cstat-no" title="statement not covered" > const response = await this.deviceRefreshStatus()</span>
1298
+ <span class="cstat-no" title="statement not covered" > const deviceStatus: any = response.body</span>
1299
+ <span class="cstat-no" title="statement not covered" > this.debugLog(`statusCode: ${deviceStatus.statusCode}, deviceStatus: ${JSON.stringify(deviceStatus)}`)</span>
1300
+ <span class="cstat-no" title="statement not covered" > if (await this.successfulStatusCodes(deviceStatus)) {</span>
1301
+ <span class="cstat-no" title="statement not covered" > this.debugSuccessLog(`statusCode: ${deviceStatus.statusCode}, deviceStatus: ${JSON.stringify(deviceStatus)}`)</span>
1302
+ <span class="cstat-no" title="statement not covered" > this.deviceStatus = deviceStatus.body</span>
1303
+ <span class="cstat-no" title="statement not covered" > await this.openAPIparseStatus()</span>
1304
+ <span class="cstat-no" title="statement not covered" > await this.updateHomeKitCharacteristics()</span>
1305
+ <span class="cstat-no" title="statement not covered" > } else {</span>
1306
+ <span class="cstat-no" title="statement not covered" > this.debugWarnLog(`statusCode: ${deviceStatus.statusCode}, deviceStatus: ${JSON.stringify(deviceStatus)}`)</span>
1307
+ <span class="cstat-no" title="statement not covered" > }</span>
1308
+ <span class="cstat-no" title="statement not covered" > } catch (e: any) {</span>
1309
+ <span class="cstat-no" title="statement not covered" > await this.apiError(e)</span>
1310
+ <span class="cstat-no" title="statement not covered" > this.errorLog(`failed openAPIRefreshStatus with ${this.device.connectionType} Connection, Error Message: ${JSON.stringify(e.message)}`)</span>
1311
+ <span class="cstat-no" title="statement not covered" > }</span>
1312
+ <span class="cstat-no" title="statement not covered" > }</span>
1313
+ &nbsp;
1314
+ <span class="cstat-no" title="statement not covered" > async registerWebhook(): Promise&lt;void&gt; {</span>
1315
+ <span class="cstat-no" title="statement not covered" > if (this.device.webhook) {</span>
1316
+ <span class="cstat-no" title="statement not covered" > this.debugLog('is listening webhook.')</span>
1317
+ <span class="cstat-no" title="statement not covered" > this.platform.webhookEventHandler[this.device.deviceId] = async (context: hub2WebhookContext) =&gt; {</span>
1318
+ <span class="cstat-no" title="statement not covered" > try {</span>
1319
+ <span class="cstat-no" title="statement not covered" > this.webhookContext = context</span>
1320
+ <span class="cstat-no" title="statement not covered" > if (context !== undefined || context !== null) {</span>
1321
+ <span class="cstat-no" title="statement not covered" > this.debugLog(`received Webhook: ${JSON.stringify(context)}`)</span>
1322
+ <span class="cstat-no" title="statement not covered" > await this.parseStatusWebhook()</span>
1323
+ <span class="cstat-no" title="statement not covered" > await this.updateHomeKitCharacteristics()</span>
1324
+ <span class="cstat-no" title="statement not covered" > } else {</span>
1325
+ <span class="cstat-no" title="statement not covered" > this.errorLog(`context is either undefined or null, context: ${JSON.stringify(context)}`)</span>
1326
+ <span class="cstat-no" title="statement not covered" > }</span>
1327
+ <span class="cstat-no" title="statement not covered" > } catch (e: any) {</span>
1328
+ <span class="cstat-no" title="statement not covered" > this.errorLog(`failed to handle webhook. Received: ${JSON.stringify(context)} Error: ${e.message ?? e}`)</span>
1329
+ <span class="cstat-no" title="statement not covered" > }</span>
1330
+ <span class="cstat-no" title="statement not covered" > }</span>
1331
+ <span class="cstat-no" title="statement not covered" > } else {</span>
1332
+ <span class="cstat-no" title="statement not covered" > this.debugLog('is not listening webhook.')</span>
1333
+ <span class="cstat-no" title="statement not covered" > }</span>
1334
+ <span class="cstat-no" title="statement not covered" > }</span>
1335
+ &nbsp;
1336
+ /**
1337
+ * Handle requests to set the value of the "Target Position" characteristic
1338
+ */
1339
+ &nbsp;
1340
+ <span class="cstat-no" title="statement not covered" > async updateHomeKitCharacteristics(): Promise&lt;void&gt; {</span>
1341
+ // CurrentRelativeHumidity
1342
+ <span class="cstat-no" title="statement not covered" > if (!(this.device as hubConfig).hide_humidity &amp;&amp; this.HumiditySensor?.Service) {</span>
1343
+ <span class="cstat-no" title="statement not covered" > await this.updateCharacteristic(this.HumiditySensor.Service, this.hap.Characteristic.CurrentRelativeHumidity, this.HumiditySensor.CurrentRelativeHumidity, 'CurrentRelativeHumidity')</span>
1344
+ <span class="cstat-no" title="statement not covered" > }</span>
1345
+ // CurrentTemperature
1346
+ <span class="cstat-no" title="statement not covered" > if (!(this.device as hubConfig).hide_temperature &amp;&amp; this.TemperatureSensor?.Service) {</span>
1347
+ <span class="cstat-no" title="statement not covered" > await this.updateCharacteristic(this.TemperatureSensor.Service, this.hap.Characteristic.CurrentTemperature, this.TemperatureSensor.CurrentTemperature, 'CurrentTemperature')</span>
1348
+ <span class="cstat-no" title="statement not covered" > }</span>
1349
+ // CurrentAmbientLightLevel
1350
+ <span class="cstat-no" title="statement not covered" > if (!(this.device as hubConfig).hide_lightsensor &amp;&amp; this.LightSensor?.Service) {</span>
1351
+ <span class="cstat-no" title="statement not covered" > await this.updateCharacteristic(this.LightSensor.Service, this.hap.Characteristic.CurrentAmbientLightLevel, this.LightSensor.CurrentAmbientLightLevel, 'CurrentAmbientLightLevel')</span>
1352
+ <span class="cstat-no" title="statement not covered" > }</span>
1353
+ <span class="cstat-no" title="statement not covered" > }</span>
1354
+ &nbsp;
1355
+ <span class="cstat-no" title="statement not covered" > async BLERefreshConnection(switchbot: SwitchBotBLE): Promise&lt;void&gt; {</span>
1356
+ <span class="cstat-no" title="statement not covered" > this.errorLog(`wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`)</span>
1357
+ <span class="cstat-no" title="statement not covered" > if (this.platform.config.credentials?.token &amp;&amp; this.device.connectionType === 'BLE/OpenAPI') {</span>
1358
+ <span class="cstat-no" title="statement not covered" > this.warnLog('Using OpenAPI Connection to Refresh Status')</span>
1359
+ <span class="cstat-no" title="statement not covered" > await this.openAPIRefreshStatus()</span>
1360
+ <span class="cstat-no" title="statement not covered" > }</span>
1361
+ <span class="cstat-no" title="statement not covered" > }</span>
1362
+ &nbsp;
1363
+ <span class="cstat-no" title="statement not covered" > async offlineOff(): Promise&lt;void&gt; {</span>
1364
+ <span class="cstat-no" title="statement not covered" > if (this.device.offline) {</span>
1365
+ <span class="cstat-no" title="statement not covered" > if (!(this.device as hubConfig).hide_temperature &amp;&amp; this.TemperatureSensor?.Service) {</span>
1366
+ <span class="cstat-no" title="statement not covered" > this.TemperatureSensor.Service.updateCharacteristic(this.hap.Characteristic.CurrentTemperature, this.accessory.context.CurrentTemperature)</span>
1367
+ <span class="cstat-no" title="statement not covered" > }</span>
1368
+ <span class="cstat-no" title="statement not covered" > if (!(this.device as hubConfig).hide_humidity &amp;&amp; this.HumiditySensor?.Service) {</span>
1369
+ <span class="cstat-no" title="statement not covered" > this.HumiditySensor.Service.updateCharacteristic(this.hap.Characteristic.CurrentRelativeHumidity, this.accessory.context.CurrentRelativeHumidity)</span>
1370
+ <span class="cstat-no" title="statement not covered" > }</span>
1371
+ <span class="cstat-no" title="statement not covered" > if (!(this.device as hubConfig).hide_lightsensor &amp;&amp; this.LightSensor?.Service) {</span>
1372
+ <span class="cstat-no" title="statement not covered" > this.LightSensor.Service.updateCharacteristic(this.hap.Characteristic.CurrentAmbientLightLevel, this.accessory.context.CurrentAmbientLightLevel)</span>
1373
+ <span class="cstat-no" title="statement not covered" > }</span>
1374
+ <span class="cstat-no" title="statement not covered" > }</span>
1375
+ <span class="cstat-no" title="statement not covered" > }</span>
1376
+ &nbsp;
1377
+ <span class="cstat-no" title="statement not covered" > async apiError(e: any): Promise&lt;void&gt; {</span>
1378
+ <span class="cstat-no" title="statement not covered" > if (!(this.device as hubConfig).hide_temperature &amp;&amp; this.TemperatureSensor?.Service) {</span>
1379
+ <span class="cstat-no" title="statement not covered" > this.TemperatureSensor.Service.updateCharacteristic(this.hap.Characteristic.CurrentTemperature, e)</span>
1380
+ <span class="cstat-no" title="statement not covered" > }</span>
1381
+ <span class="cstat-no" title="statement not covered" > if (!(this.device as hubConfig).hide_humidity &amp;&amp; this.HumiditySensor?.Service) {</span>
1382
+ <span class="cstat-no" title="statement not covered" > this.HumiditySensor.Service.updateCharacteristic(this.hap.Characteristic.CurrentRelativeHumidity, e)</span>
1383
+ <span class="cstat-no" title="statement not covered" > }</span>
1384
+ <span class="cstat-no" title="statement not covered" > if (!(this.device as hubConfig).hide_lightsensor &amp;&amp; this.LightSensor?.Service) {</span>
1385
+ <span class="cstat-no" title="statement not covered" > this.LightSensor.Service.updateCharacteristic(this.hap.Characteristic.CurrentAmbientLightLevel, e)</span>
1386
+ <span class="cstat-no" title="statement not covered" > }</span>
1387
+ <span class="cstat-no" title="statement not covered" > }</span>
1388
+ <span class="cstat-no" title="statement not covered" >}</span>
1389
+ &nbsp;</pre></td></tr></table></pre>
1390
+
1391
+ <div class='push'></div><!-- for sticky footer -->
1392
+ </div><!-- /wrapper -->
1393
+ <div class='footer quiet pad2 space-top1 center small'>
1394
+ Code coverage generated by
1395
+ <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
1396
+ at 2025-08-21T05:12:41.588Z
1397
+ </div>
1398
+ <script src="../../prettify.js"></script>
1399
+ <script>
1400
+ window.onload = function () {
1401
+ prettyPrint();
1402
+ };
1403
+ </script>
1404
+ <script src="../../sorter.js"></script>
1405
+ <script src="../../block-navigation.js"></script>
1406
+ </body>
1407
+ </html>
1408
+