mqtt-plus 1.4.13 → 1.4.15

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 (92) hide show
  1. package/AGENTS.md +0 -1
  2. package/CHANGELOG.md +18 -0
  3. package/dst-stage1/mqtt-plus-api.js +1 -0
  4. package/dst-stage1/mqtt-plus-api.js.map +1 -0
  5. package/dst-stage1/mqtt-plus-auth.js +1 -0
  6. package/dst-stage1/mqtt-plus-auth.js.map +1 -0
  7. package/dst-stage1/mqtt-plus-base.js +1 -0
  8. package/dst-stage1/mqtt-plus-base.js.map +1 -0
  9. package/dst-stage1/mqtt-plus-codec.js +1 -0
  10. package/dst-stage1/mqtt-plus-codec.js.map +1 -0
  11. package/dst-stage1/mqtt-plus-encode.js +1 -0
  12. package/dst-stage1/mqtt-plus-encode.js.map +1 -0
  13. package/dst-stage1/mqtt-plus-error.js +1 -0
  14. package/dst-stage1/mqtt-plus-error.js.map +1 -0
  15. package/dst-stage1/mqtt-plus-event.js +1 -0
  16. package/dst-stage1/mqtt-plus-event.js.map +1 -0
  17. package/dst-stage1/mqtt-plus-info.js +1 -0
  18. package/dst-stage1/mqtt-plus-info.js.map +1 -0
  19. package/dst-stage1/mqtt-plus-meta.js +1 -0
  20. package/dst-stage1/mqtt-plus-meta.js.map +1 -0
  21. package/dst-stage1/mqtt-plus-msg.js +1 -0
  22. package/dst-stage1/mqtt-plus-msg.js.map +1 -0
  23. package/dst-stage1/mqtt-plus-options.js +1 -0
  24. package/dst-stage1/mqtt-plus-options.js.map +1 -0
  25. package/dst-stage1/mqtt-plus-service.js +1 -0
  26. package/dst-stage1/mqtt-plus-service.js.map +1 -0
  27. package/dst-stage1/mqtt-plus-sink.js +14 -2
  28. package/dst-stage1/mqtt-plus-sink.js.map +1 -0
  29. package/dst-stage1/mqtt-plus-source.js +27 -16
  30. package/dst-stage1/mqtt-plus-source.js.map +1 -0
  31. package/dst-stage1/mqtt-plus-subscription.js +1 -0
  32. package/dst-stage1/mqtt-plus-subscription.js.map +1 -0
  33. package/dst-stage1/mqtt-plus-timer.js +1 -0
  34. package/dst-stage1/mqtt-plus-timer.js.map +1 -0
  35. package/dst-stage1/mqtt-plus-trace.js +1 -0
  36. package/dst-stage1/mqtt-plus-trace.js.map +1 -0
  37. package/dst-stage1/mqtt-plus-util.js +1 -0
  38. package/dst-stage1/mqtt-plus-util.js.map +1 -0
  39. package/dst-stage1/mqtt-plus-version.d.ts +1 -1
  40. package/dst-stage1/mqtt-plus-version.js +3 -1
  41. package/dst-stage1/mqtt-plus-version.js.map +1 -0
  42. package/dst-stage1/mqtt-plus.js +1 -0
  43. package/dst-stage1/mqtt-plus.js.map +1 -0
  44. package/dst-stage2/mqtt-plus.cjs.js +1972 -2161
  45. package/dst-stage2/mqtt-plus.esm.js +1934 -2131
  46. package/dst-stage2/mqtt-plus.umd.js +13 -14
  47. package/etc/c8.json +16 -0
  48. package/etc/knip.jsonc +7 -1
  49. package/etc/stx.conf +36 -4
  50. package/etc/tsc.json +1 -1
  51. package/etc/vite.mts +11 -5
  52. package/package.d/vite+8.0.0.patch +12 -0
  53. package/package.json +12 -3
  54. package/src/mqtt-plus-sink.ts +14 -2
  55. package/src/mqtt-plus-source.ts +27 -16
  56. package/src/mqtt-plus-version.ts +2 -3
  57. package/tst/.c8/base.css +224 -0
  58. package/tst/.c8/block-navigation.js +87 -0
  59. package/tst/.c8/favicon.png +0 -0
  60. package/tst/.c8/index.html +371 -0
  61. package/tst/.c8/mqtt-plus-auth.ts.html +538 -0
  62. package/tst/.c8/mqtt-plus-base.ts.html +826 -0
  63. package/tst/.c8/mqtt-plus-codec.ts.html +457 -0
  64. package/tst/.c8/mqtt-plus-encode.ts.html +310 -0
  65. package/tst/.c8/mqtt-plus-error.ts.html +1186 -0
  66. package/tst/.c8/mqtt-plus-event.ts.html +733 -0
  67. package/tst/.c8/mqtt-plus-meta.ts.html +271 -0
  68. package/tst/.c8/mqtt-plus-msg.ts.html +1693 -0
  69. package/tst/.c8/mqtt-plus-options.ts.html +319 -0
  70. package/tst/.c8/mqtt-plus-service.ts.html +865 -0
  71. package/tst/.c8/mqtt-plus-sink.ts.html +1645 -0
  72. package/tst/.c8/mqtt-plus-source.ts.html +1585 -0
  73. package/tst/.c8/mqtt-plus-subscription.ts.html +706 -0
  74. package/tst/.c8/mqtt-plus-timer.ts.html +286 -0
  75. package/tst/.c8/mqtt-plus-trace.ts.html +463 -0
  76. package/tst/.c8/mqtt-plus-util.ts.html +823 -0
  77. package/tst/.c8/mqtt-plus-version.ts.html +205 -0
  78. package/tst/.c8/mqtt-plus.ts.html +193 -0
  79. package/tst/.c8/prettify.css +1 -0
  80. package/tst/.c8/prettify.js +2 -0
  81. package/tst/.c8/sort-arrow-sprite.png +0 -0
  82. package/tst/.c8/sorter.js +210 -0
  83. package/tst/.c8/tmp/coverage-6577-1773528098323-2.json +1 -0
  84. package/tst/.c8/tmp/coverage-6577-1773528098331-1.json +1 -0
  85. package/tst/.c8/tmp/coverage-6577-1773528098353-0.json +1 -0
  86. package/tst/.c8/tmp/coverage-6578-1773528089194-0.json +1 -0
  87. package/tst/mqtt-plus-2-event.spec.ts +29 -0
  88. package/tst/mqtt-plus-6-misc.spec.ts +79 -2
  89. package/tst/mqtt-plus-7-spool.spec.ts +101 -0
  90. package/tst/mqtt-plus-8-run.spec.ts +115 -0
  91. package/tst/{tsc.json → tsc.cov.json} +4 -3
  92. package/tst/tsc.std.json +31 -0
@@ -0,0 +1,1645 @@
1
+
2
+ <!doctype html>
3
+ <html lang="en">
4
+
5
+ <head>
6
+ <title>Code coverage report for mqtt-plus-sink.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> mqtt-plus-sink.ts</h1>
23
+ <div class='clearfix'>
24
+
25
+ <div class='fl pad1y space-right2'>
26
+ <span class="strong">94.8% </span>
27
+ <span class="quiet">Statements</span>
28
+ <span class='fraction'>493/520</span>
29
+ </div>
30
+
31
+
32
+ <div class='fl pad1y space-right2'>
33
+ <span class="strong">67.77% </span>
34
+ <span class="quiet">Branches</span>
35
+ <span class='fraction'>61/90</span>
36
+ </div>
37
+
38
+
39
+ <div class='fl pad1y space-right2'>
40
+ <span class="strong">100% </span>
41
+ <span class="quiet">Functions</span>
42
+ <span class='fraction'>13/13</span>
43
+ </div>
44
+
45
+
46
+ <div class='fl pad1y space-right2'>
47
+ <span class="strong">94.8% </span>
48
+ <span class="quiet">Lines</span>
49
+ <span class='fraction'>493/520</span>
50
+ </div>
51
+
52
+
53
+ </div>
54
+ <p class="quiet">
55
+ Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block.
56
+ </p>
57
+ <template id="filterTemplate">
58
+ <div class="quiet">
59
+ Filter:
60
+ <input type="search" id="fileSearch">
61
+ </div>
62
+ </template>
63
+ </div>
64
+ <div class='status-line high'></div>
65
+ <pre><table class="coverage">
66
+ <tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
67
+ <a name='L2'></a><a href='#L2'>2</a>
68
+ <a name='L3'></a><a href='#L3'>3</a>
69
+ <a name='L4'></a><a href='#L4'>4</a>
70
+ <a name='L5'></a><a href='#L5'>5</a>
71
+ <a name='L6'></a><a href='#L6'>6</a>
72
+ <a name='L7'></a><a href='#L7'>7</a>
73
+ <a name='L8'></a><a href='#L8'>8</a>
74
+ <a name='L9'></a><a href='#L9'>9</a>
75
+ <a name='L10'></a><a href='#L10'>10</a>
76
+ <a name='L11'></a><a href='#L11'>11</a>
77
+ <a name='L12'></a><a href='#L12'>12</a>
78
+ <a name='L13'></a><a href='#L13'>13</a>
79
+ <a name='L14'></a><a href='#L14'>14</a>
80
+ <a name='L15'></a><a href='#L15'>15</a>
81
+ <a name='L16'></a><a href='#L16'>16</a>
82
+ <a name='L17'></a><a href='#L17'>17</a>
83
+ <a name='L18'></a><a href='#L18'>18</a>
84
+ <a name='L19'></a><a href='#L19'>19</a>
85
+ <a name='L20'></a><a href='#L20'>20</a>
86
+ <a name='L21'></a><a href='#L21'>21</a>
87
+ <a name='L22'></a><a href='#L22'>22</a>
88
+ <a name='L23'></a><a href='#L23'>23</a>
89
+ <a name='L24'></a><a href='#L24'>24</a>
90
+ <a name='L25'></a><a href='#L25'>25</a>
91
+ <a name='L26'></a><a href='#L26'>26</a>
92
+ <a name='L27'></a><a href='#L27'>27</a>
93
+ <a name='L28'></a><a href='#L28'>28</a>
94
+ <a name='L29'></a><a href='#L29'>29</a>
95
+ <a name='L30'></a><a href='#L30'>30</a>
96
+ <a name='L31'></a><a href='#L31'>31</a>
97
+ <a name='L32'></a><a href='#L32'>32</a>
98
+ <a name='L33'></a><a href='#L33'>33</a>
99
+ <a name='L34'></a><a href='#L34'>34</a>
100
+ <a name='L35'></a><a href='#L35'>35</a>
101
+ <a name='L36'></a><a href='#L36'>36</a>
102
+ <a name='L37'></a><a href='#L37'>37</a>
103
+ <a name='L38'></a><a href='#L38'>38</a>
104
+ <a name='L39'></a><a href='#L39'>39</a>
105
+ <a name='L40'></a><a href='#L40'>40</a>
106
+ <a name='L41'></a><a href='#L41'>41</a>
107
+ <a name='L42'></a><a href='#L42'>42</a>
108
+ <a name='L43'></a><a href='#L43'>43</a>
109
+ <a name='L44'></a><a href='#L44'>44</a>
110
+ <a name='L45'></a><a href='#L45'>45</a>
111
+ <a name='L46'></a><a href='#L46'>46</a>
112
+ <a name='L47'></a><a href='#L47'>47</a>
113
+ <a name='L48'></a><a href='#L48'>48</a>
114
+ <a name='L49'></a><a href='#L49'>49</a>
115
+ <a name='L50'></a><a href='#L50'>50</a>
116
+ <a name='L51'></a><a href='#L51'>51</a>
117
+ <a name='L52'></a><a href='#L52'>52</a>
118
+ <a name='L53'></a><a href='#L53'>53</a>
119
+ <a name='L54'></a><a href='#L54'>54</a>
120
+ <a name='L55'></a><a href='#L55'>55</a>
121
+ <a name='L56'></a><a href='#L56'>56</a>
122
+ <a name='L57'></a><a href='#L57'>57</a>
123
+ <a name='L58'></a><a href='#L58'>58</a>
124
+ <a name='L59'></a><a href='#L59'>59</a>
125
+ <a name='L60'></a><a href='#L60'>60</a>
126
+ <a name='L61'></a><a href='#L61'>61</a>
127
+ <a name='L62'></a><a href='#L62'>62</a>
128
+ <a name='L63'></a><a href='#L63'>63</a>
129
+ <a name='L64'></a><a href='#L64'>64</a>
130
+ <a name='L65'></a><a href='#L65'>65</a>
131
+ <a name='L66'></a><a href='#L66'>66</a>
132
+ <a name='L67'></a><a href='#L67'>67</a>
133
+ <a name='L68'></a><a href='#L68'>68</a>
134
+ <a name='L69'></a><a href='#L69'>69</a>
135
+ <a name='L70'></a><a href='#L70'>70</a>
136
+ <a name='L71'></a><a href='#L71'>71</a>
137
+ <a name='L72'></a><a href='#L72'>72</a>
138
+ <a name='L73'></a><a href='#L73'>73</a>
139
+ <a name='L74'></a><a href='#L74'>74</a>
140
+ <a name='L75'></a><a href='#L75'>75</a>
141
+ <a name='L76'></a><a href='#L76'>76</a>
142
+ <a name='L77'></a><a href='#L77'>77</a>
143
+ <a name='L78'></a><a href='#L78'>78</a>
144
+ <a name='L79'></a><a href='#L79'>79</a>
145
+ <a name='L80'></a><a href='#L80'>80</a>
146
+ <a name='L81'></a><a href='#L81'>81</a>
147
+ <a name='L82'></a><a href='#L82'>82</a>
148
+ <a name='L83'></a><a href='#L83'>83</a>
149
+ <a name='L84'></a><a href='#L84'>84</a>
150
+ <a name='L85'></a><a href='#L85'>85</a>
151
+ <a name='L86'></a><a href='#L86'>86</a>
152
+ <a name='L87'></a><a href='#L87'>87</a>
153
+ <a name='L88'></a><a href='#L88'>88</a>
154
+ <a name='L89'></a><a href='#L89'>89</a>
155
+ <a name='L90'></a><a href='#L90'>90</a>
156
+ <a name='L91'></a><a href='#L91'>91</a>
157
+ <a name='L92'></a><a href='#L92'>92</a>
158
+ <a name='L93'></a><a href='#L93'>93</a>
159
+ <a name='L94'></a><a href='#L94'>94</a>
160
+ <a name='L95'></a><a href='#L95'>95</a>
161
+ <a name='L96'></a><a href='#L96'>96</a>
162
+ <a name='L97'></a><a href='#L97'>97</a>
163
+ <a name='L98'></a><a href='#L98'>98</a>
164
+ <a name='L99'></a><a href='#L99'>99</a>
165
+ <a name='L100'></a><a href='#L100'>100</a>
166
+ <a name='L101'></a><a href='#L101'>101</a>
167
+ <a name='L102'></a><a href='#L102'>102</a>
168
+ <a name='L103'></a><a href='#L103'>103</a>
169
+ <a name='L104'></a><a href='#L104'>104</a>
170
+ <a name='L105'></a><a href='#L105'>105</a>
171
+ <a name='L106'></a><a href='#L106'>106</a>
172
+ <a name='L107'></a><a href='#L107'>107</a>
173
+ <a name='L108'></a><a href='#L108'>108</a>
174
+ <a name='L109'></a><a href='#L109'>109</a>
175
+ <a name='L110'></a><a href='#L110'>110</a>
176
+ <a name='L111'></a><a href='#L111'>111</a>
177
+ <a name='L112'></a><a href='#L112'>112</a>
178
+ <a name='L113'></a><a href='#L113'>113</a>
179
+ <a name='L114'></a><a href='#L114'>114</a>
180
+ <a name='L115'></a><a href='#L115'>115</a>
181
+ <a name='L116'></a><a href='#L116'>116</a>
182
+ <a name='L117'></a><a href='#L117'>117</a>
183
+ <a name='L118'></a><a href='#L118'>118</a>
184
+ <a name='L119'></a><a href='#L119'>119</a>
185
+ <a name='L120'></a><a href='#L120'>120</a>
186
+ <a name='L121'></a><a href='#L121'>121</a>
187
+ <a name='L122'></a><a href='#L122'>122</a>
188
+ <a name='L123'></a><a href='#L123'>123</a>
189
+ <a name='L124'></a><a href='#L124'>124</a>
190
+ <a name='L125'></a><a href='#L125'>125</a>
191
+ <a name='L126'></a><a href='#L126'>126</a>
192
+ <a name='L127'></a><a href='#L127'>127</a>
193
+ <a name='L128'></a><a href='#L128'>128</a>
194
+ <a name='L129'></a><a href='#L129'>129</a>
195
+ <a name='L130'></a><a href='#L130'>130</a>
196
+ <a name='L131'></a><a href='#L131'>131</a>
197
+ <a name='L132'></a><a href='#L132'>132</a>
198
+ <a name='L133'></a><a href='#L133'>133</a>
199
+ <a name='L134'></a><a href='#L134'>134</a>
200
+ <a name='L135'></a><a href='#L135'>135</a>
201
+ <a name='L136'></a><a href='#L136'>136</a>
202
+ <a name='L137'></a><a href='#L137'>137</a>
203
+ <a name='L138'></a><a href='#L138'>138</a>
204
+ <a name='L139'></a><a href='#L139'>139</a>
205
+ <a name='L140'></a><a href='#L140'>140</a>
206
+ <a name='L141'></a><a href='#L141'>141</a>
207
+ <a name='L142'></a><a href='#L142'>142</a>
208
+ <a name='L143'></a><a href='#L143'>143</a>
209
+ <a name='L144'></a><a href='#L144'>144</a>
210
+ <a name='L145'></a><a href='#L145'>145</a>
211
+ <a name='L146'></a><a href='#L146'>146</a>
212
+ <a name='L147'></a><a href='#L147'>147</a>
213
+ <a name='L148'></a><a href='#L148'>148</a>
214
+ <a name='L149'></a><a href='#L149'>149</a>
215
+ <a name='L150'></a><a href='#L150'>150</a>
216
+ <a name='L151'></a><a href='#L151'>151</a>
217
+ <a name='L152'></a><a href='#L152'>152</a>
218
+ <a name='L153'></a><a href='#L153'>153</a>
219
+ <a name='L154'></a><a href='#L154'>154</a>
220
+ <a name='L155'></a><a href='#L155'>155</a>
221
+ <a name='L156'></a><a href='#L156'>156</a>
222
+ <a name='L157'></a><a href='#L157'>157</a>
223
+ <a name='L158'></a><a href='#L158'>158</a>
224
+ <a name='L159'></a><a href='#L159'>159</a>
225
+ <a name='L160'></a><a href='#L160'>160</a>
226
+ <a name='L161'></a><a href='#L161'>161</a>
227
+ <a name='L162'></a><a href='#L162'>162</a>
228
+ <a name='L163'></a><a href='#L163'>163</a>
229
+ <a name='L164'></a><a href='#L164'>164</a>
230
+ <a name='L165'></a><a href='#L165'>165</a>
231
+ <a name='L166'></a><a href='#L166'>166</a>
232
+ <a name='L167'></a><a href='#L167'>167</a>
233
+ <a name='L168'></a><a href='#L168'>168</a>
234
+ <a name='L169'></a><a href='#L169'>169</a>
235
+ <a name='L170'></a><a href='#L170'>170</a>
236
+ <a name='L171'></a><a href='#L171'>171</a>
237
+ <a name='L172'></a><a href='#L172'>172</a>
238
+ <a name='L173'></a><a href='#L173'>173</a>
239
+ <a name='L174'></a><a href='#L174'>174</a>
240
+ <a name='L175'></a><a href='#L175'>175</a>
241
+ <a name='L176'></a><a href='#L176'>176</a>
242
+ <a name='L177'></a><a href='#L177'>177</a>
243
+ <a name='L178'></a><a href='#L178'>178</a>
244
+ <a name='L179'></a><a href='#L179'>179</a>
245
+ <a name='L180'></a><a href='#L180'>180</a>
246
+ <a name='L181'></a><a href='#L181'>181</a>
247
+ <a name='L182'></a><a href='#L182'>182</a>
248
+ <a name='L183'></a><a href='#L183'>183</a>
249
+ <a name='L184'></a><a href='#L184'>184</a>
250
+ <a name='L185'></a><a href='#L185'>185</a>
251
+ <a name='L186'></a><a href='#L186'>186</a>
252
+ <a name='L187'></a><a href='#L187'>187</a>
253
+ <a name='L188'></a><a href='#L188'>188</a>
254
+ <a name='L189'></a><a href='#L189'>189</a>
255
+ <a name='L190'></a><a href='#L190'>190</a>
256
+ <a name='L191'></a><a href='#L191'>191</a>
257
+ <a name='L192'></a><a href='#L192'>192</a>
258
+ <a name='L193'></a><a href='#L193'>193</a>
259
+ <a name='L194'></a><a href='#L194'>194</a>
260
+ <a name='L195'></a><a href='#L195'>195</a>
261
+ <a name='L196'></a><a href='#L196'>196</a>
262
+ <a name='L197'></a><a href='#L197'>197</a>
263
+ <a name='L198'></a><a href='#L198'>198</a>
264
+ <a name='L199'></a><a href='#L199'>199</a>
265
+ <a name='L200'></a><a href='#L200'>200</a>
266
+ <a name='L201'></a><a href='#L201'>201</a>
267
+ <a name='L202'></a><a href='#L202'>202</a>
268
+ <a name='L203'></a><a href='#L203'>203</a>
269
+ <a name='L204'></a><a href='#L204'>204</a>
270
+ <a name='L205'></a><a href='#L205'>205</a>
271
+ <a name='L206'></a><a href='#L206'>206</a>
272
+ <a name='L207'></a><a href='#L207'>207</a>
273
+ <a name='L208'></a><a href='#L208'>208</a>
274
+ <a name='L209'></a><a href='#L209'>209</a>
275
+ <a name='L210'></a><a href='#L210'>210</a>
276
+ <a name='L211'></a><a href='#L211'>211</a>
277
+ <a name='L212'></a><a href='#L212'>212</a>
278
+ <a name='L213'></a><a href='#L213'>213</a>
279
+ <a name='L214'></a><a href='#L214'>214</a>
280
+ <a name='L215'></a><a href='#L215'>215</a>
281
+ <a name='L216'></a><a href='#L216'>216</a>
282
+ <a name='L217'></a><a href='#L217'>217</a>
283
+ <a name='L218'></a><a href='#L218'>218</a>
284
+ <a name='L219'></a><a href='#L219'>219</a>
285
+ <a name='L220'></a><a href='#L220'>220</a>
286
+ <a name='L221'></a><a href='#L221'>221</a>
287
+ <a name='L222'></a><a href='#L222'>222</a>
288
+ <a name='L223'></a><a href='#L223'>223</a>
289
+ <a name='L224'></a><a href='#L224'>224</a>
290
+ <a name='L225'></a><a href='#L225'>225</a>
291
+ <a name='L226'></a><a href='#L226'>226</a>
292
+ <a name='L227'></a><a href='#L227'>227</a>
293
+ <a name='L228'></a><a href='#L228'>228</a>
294
+ <a name='L229'></a><a href='#L229'>229</a>
295
+ <a name='L230'></a><a href='#L230'>230</a>
296
+ <a name='L231'></a><a href='#L231'>231</a>
297
+ <a name='L232'></a><a href='#L232'>232</a>
298
+ <a name='L233'></a><a href='#L233'>233</a>
299
+ <a name='L234'></a><a href='#L234'>234</a>
300
+ <a name='L235'></a><a href='#L235'>235</a>
301
+ <a name='L236'></a><a href='#L236'>236</a>
302
+ <a name='L237'></a><a href='#L237'>237</a>
303
+ <a name='L238'></a><a href='#L238'>238</a>
304
+ <a name='L239'></a><a href='#L239'>239</a>
305
+ <a name='L240'></a><a href='#L240'>240</a>
306
+ <a name='L241'></a><a href='#L241'>241</a>
307
+ <a name='L242'></a><a href='#L242'>242</a>
308
+ <a name='L243'></a><a href='#L243'>243</a>
309
+ <a name='L244'></a><a href='#L244'>244</a>
310
+ <a name='L245'></a><a href='#L245'>245</a>
311
+ <a name='L246'></a><a href='#L246'>246</a>
312
+ <a name='L247'></a><a href='#L247'>247</a>
313
+ <a name='L248'></a><a href='#L248'>248</a>
314
+ <a name='L249'></a><a href='#L249'>249</a>
315
+ <a name='L250'></a><a href='#L250'>250</a>
316
+ <a name='L251'></a><a href='#L251'>251</a>
317
+ <a name='L252'></a><a href='#L252'>252</a>
318
+ <a name='L253'></a><a href='#L253'>253</a>
319
+ <a name='L254'></a><a href='#L254'>254</a>
320
+ <a name='L255'></a><a href='#L255'>255</a>
321
+ <a name='L256'></a><a href='#L256'>256</a>
322
+ <a name='L257'></a><a href='#L257'>257</a>
323
+ <a name='L258'></a><a href='#L258'>258</a>
324
+ <a name='L259'></a><a href='#L259'>259</a>
325
+ <a name='L260'></a><a href='#L260'>260</a>
326
+ <a name='L261'></a><a href='#L261'>261</a>
327
+ <a name='L262'></a><a href='#L262'>262</a>
328
+ <a name='L263'></a><a href='#L263'>263</a>
329
+ <a name='L264'></a><a href='#L264'>264</a>
330
+ <a name='L265'></a><a href='#L265'>265</a>
331
+ <a name='L266'></a><a href='#L266'>266</a>
332
+ <a name='L267'></a><a href='#L267'>267</a>
333
+ <a name='L268'></a><a href='#L268'>268</a>
334
+ <a name='L269'></a><a href='#L269'>269</a>
335
+ <a name='L270'></a><a href='#L270'>270</a>
336
+ <a name='L271'></a><a href='#L271'>271</a>
337
+ <a name='L272'></a><a href='#L272'>272</a>
338
+ <a name='L273'></a><a href='#L273'>273</a>
339
+ <a name='L274'></a><a href='#L274'>274</a>
340
+ <a name='L275'></a><a href='#L275'>275</a>
341
+ <a name='L276'></a><a href='#L276'>276</a>
342
+ <a name='L277'></a><a href='#L277'>277</a>
343
+ <a name='L278'></a><a href='#L278'>278</a>
344
+ <a name='L279'></a><a href='#L279'>279</a>
345
+ <a name='L280'></a><a href='#L280'>280</a>
346
+ <a name='L281'></a><a href='#L281'>281</a>
347
+ <a name='L282'></a><a href='#L282'>282</a>
348
+ <a name='L283'></a><a href='#L283'>283</a>
349
+ <a name='L284'></a><a href='#L284'>284</a>
350
+ <a name='L285'></a><a href='#L285'>285</a>
351
+ <a name='L286'></a><a href='#L286'>286</a>
352
+ <a name='L287'></a><a href='#L287'>287</a>
353
+ <a name='L288'></a><a href='#L288'>288</a>
354
+ <a name='L289'></a><a href='#L289'>289</a>
355
+ <a name='L290'></a><a href='#L290'>290</a>
356
+ <a name='L291'></a><a href='#L291'>291</a>
357
+ <a name='L292'></a><a href='#L292'>292</a>
358
+ <a name='L293'></a><a href='#L293'>293</a>
359
+ <a name='L294'></a><a href='#L294'>294</a>
360
+ <a name='L295'></a><a href='#L295'>295</a>
361
+ <a name='L296'></a><a href='#L296'>296</a>
362
+ <a name='L297'></a><a href='#L297'>297</a>
363
+ <a name='L298'></a><a href='#L298'>298</a>
364
+ <a name='L299'></a><a href='#L299'>299</a>
365
+ <a name='L300'></a><a href='#L300'>300</a>
366
+ <a name='L301'></a><a href='#L301'>301</a>
367
+ <a name='L302'></a><a href='#L302'>302</a>
368
+ <a name='L303'></a><a href='#L303'>303</a>
369
+ <a name='L304'></a><a href='#L304'>304</a>
370
+ <a name='L305'></a><a href='#L305'>305</a>
371
+ <a name='L306'></a><a href='#L306'>306</a>
372
+ <a name='L307'></a><a href='#L307'>307</a>
373
+ <a name='L308'></a><a href='#L308'>308</a>
374
+ <a name='L309'></a><a href='#L309'>309</a>
375
+ <a name='L310'></a><a href='#L310'>310</a>
376
+ <a name='L311'></a><a href='#L311'>311</a>
377
+ <a name='L312'></a><a href='#L312'>312</a>
378
+ <a name='L313'></a><a href='#L313'>313</a>
379
+ <a name='L314'></a><a href='#L314'>314</a>
380
+ <a name='L315'></a><a href='#L315'>315</a>
381
+ <a name='L316'></a><a href='#L316'>316</a>
382
+ <a name='L317'></a><a href='#L317'>317</a>
383
+ <a name='L318'></a><a href='#L318'>318</a>
384
+ <a name='L319'></a><a href='#L319'>319</a>
385
+ <a name='L320'></a><a href='#L320'>320</a>
386
+ <a name='L321'></a><a href='#L321'>321</a>
387
+ <a name='L322'></a><a href='#L322'>322</a>
388
+ <a name='L323'></a><a href='#L323'>323</a>
389
+ <a name='L324'></a><a href='#L324'>324</a>
390
+ <a name='L325'></a><a href='#L325'>325</a>
391
+ <a name='L326'></a><a href='#L326'>326</a>
392
+ <a name='L327'></a><a href='#L327'>327</a>
393
+ <a name='L328'></a><a href='#L328'>328</a>
394
+ <a name='L329'></a><a href='#L329'>329</a>
395
+ <a name='L330'></a><a href='#L330'>330</a>
396
+ <a name='L331'></a><a href='#L331'>331</a>
397
+ <a name='L332'></a><a href='#L332'>332</a>
398
+ <a name='L333'></a><a href='#L333'>333</a>
399
+ <a name='L334'></a><a href='#L334'>334</a>
400
+ <a name='L335'></a><a href='#L335'>335</a>
401
+ <a name='L336'></a><a href='#L336'>336</a>
402
+ <a name='L337'></a><a href='#L337'>337</a>
403
+ <a name='L338'></a><a href='#L338'>338</a>
404
+ <a name='L339'></a><a href='#L339'>339</a>
405
+ <a name='L340'></a><a href='#L340'>340</a>
406
+ <a name='L341'></a><a href='#L341'>341</a>
407
+ <a name='L342'></a><a href='#L342'>342</a>
408
+ <a name='L343'></a><a href='#L343'>343</a>
409
+ <a name='L344'></a><a href='#L344'>344</a>
410
+ <a name='L345'></a><a href='#L345'>345</a>
411
+ <a name='L346'></a><a href='#L346'>346</a>
412
+ <a name='L347'></a><a href='#L347'>347</a>
413
+ <a name='L348'></a><a href='#L348'>348</a>
414
+ <a name='L349'></a><a href='#L349'>349</a>
415
+ <a name='L350'></a><a href='#L350'>350</a>
416
+ <a name='L351'></a><a href='#L351'>351</a>
417
+ <a name='L352'></a><a href='#L352'>352</a>
418
+ <a name='L353'></a><a href='#L353'>353</a>
419
+ <a name='L354'></a><a href='#L354'>354</a>
420
+ <a name='L355'></a><a href='#L355'>355</a>
421
+ <a name='L356'></a><a href='#L356'>356</a>
422
+ <a name='L357'></a><a href='#L357'>357</a>
423
+ <a name='L358'></a><a href='#L358'>358</a>
424
+ <a name='L359'></a><a href='#L359'>359</a>
425
+ <a name='L360'></a><a href='#L360'>360</a>
426
+ <a name='L361'></a><a href='#L361'>361</a>
427
+ <a name='L362'></a><a href='#L362'>362</a>
428
+ <a name='L363'></a><a href='#L363'>363</a>
429
+ <a name='L364'></a><a href='#L364'>364</a>
430
+ <a name='L365'></a><a href='#L365'>365</a>
431
+ <a name='L366'></a><a href='#L366'>366</a>
432
+ <a name='L367'></a><a href='#L367'>367</a>
433
+ <a name='L368'></a><a href='#L368'>368</a>
434
+ <a name='L369'></a><a href='#L369'>369</a>
435
+ <a name='L370'></a><a href='#L370'>370</a>
436
+ <a name='L371'></a><a href='#L371'>371</a>
437
+ <a name='L372'></a><a href='#L372'>372</a>
438
+ <a name='L373'></a><a href='#L373'>373</a>
439
+ <a name='L374'></a><a href='#L374'>374</a>
440
+ <a name='L375'></a><a href='#L375'>375</a>
441
+ <a name='L376'></a><a href='#L376'>376</a>
442
+ <a name='L377'></a><a href='#L377'>377</a>
443
+ <a name='L378'></a><a href='#L378'>378</a>
444
+ <a name='L379'></a><a href='#L379'>379</a>
445
+ <a name='L380'></a><a href='#L380'>380</a>
446
+ <a name='L381'></a><a href='#L381'>381</a>
447
+ <a name='L382'></a><a href='#L382'>382</a>
448
+ <a name='L383'></a><a href='#L383'>383</a>
449
+ <a name='L384'></a><a href='#L384'>384</a>
450
+ <a name='L385'></a><a href='#L385'>385</a>
451
+ <a name='L386'></a><a href='#L386'>386</a>
452
+ <a name='L387'></a><a href='#L387'>387</a>
453
+ <a name='L388'></a><a href='#L388'>388</a>
454
+ <a name='L389'></a><a href='#L389'>389</a>
455
+ <a name='L390'></a><a href='#L390'>390</a>
456
+ <a name='L391'></a><a href='#L391'>391</a>
457
+ <a name='L392'></a><a href='#L392'>392</a>
458
+ <a name='L393'></a><a href='#L393'>393</a>
459
+ <a name='L394'></a><a href='#L394'>394</a>
460
+ <a name='L395'></a><a href='#L395'>395</a>
461
+ <a name='L396'></a><a href='#L396'>396</a>
462
+ <a name='L397'></a><a href='#L397'>397</a>
463
+ <a name='L398'></a><a href='#L398'>398</a>
464
+ <a name='L399'></a><a href='#L399'>399</a>
465
+ <a name='L400'></a><a href='#L400'>400</a>
466
+ <a name='L401'></a><a href='#L401'>401</a>
467
+ <a name='L402'></a><a href='#L402'>402</a>
468
+ <a name='L403'></a><a href='#L403'>403</a>
469
+ <a name='L404'></a><a href='#L404'>404</a>
470
+ <a name='L405'></a><a href='#L405'>405</a>
471
+ <a name='L406'></a><a href='#L406'>406</a>
472
+ <a name='L407'></a><a href='#L407'>407</a>
473
+ <a name='L408'></a><a href='#L408'>408</a>
474
+ <a name='L409'></a><a href='#L409'>409</a>
475
+ <a name='L410'></a><a href='#L410'>410</a>
476
+ <a name='L411'></a><a href='#L411'>411</a>
477
+ <a name='L412'></a><a href='#L412'>412</a>
478
+ <a name='L413'></a><a href='#L413'>413</a>
479
+ <a name='L414'></a><a href='#L414'>414</a>
480
+ <a name='L415'></a><a href='#L415'>415</a>
481
+ <a name='L416'></a><a href='#L416'>416</a>
482
+ <a name='L417'></a><a href='#L417'>417</a>
483
+ <a name='L418'></a><a href='#L418'>418</a>
484
+ <a name='L419'></a><a href='#L419'>419</a>
485
+ <a name='L420'></a><a href='#L420'>420</a>
486
+ <a name='L421'></a><a href='#L421'>421</a>
487
+ <a name='L422'></a><a href='#L422'>422</a>
488
+ <a name='L423'></a><a href='#L423'>423</a>
489
+ <a name='L424'></a><a href='#L424'>424</a>
490
+ <a name='L425'></a><a href='#L425'>425</a>
491
+ <a name='L426'></a><a href='#L426'>426</a>
492
+ <a name='L427'></a><a href='#L427'>427</a>
493
+ <a name='L428'></a><a href='#L428'>428</a>
494
+ <a name='L429'></a><a href='#L429'>429</a>
495
+ <a name='L430'></a><a href='#L430'>430</a>
496
+ <a name='L431'></a><a href='#L431'>431</a>
497
+ <a name='L432'></a><a href='#L432'>432</a>
498
+ <a name='L433'></a><a href='#L433'>433</a>
499
+ <a name='L434'></a><a href='#L434'>434</a>
500
+ <a name='L435'></a><a href='#L435'>435</a>
501
+ <a name='L436'></a><a href='#L436'>436</a>
502
+ <a name='L437'></a><a href='#L437'>437</a>
503
+ <a name='L438'></a><a href='#L438'>438</a>
504
+ <a name='L439'></a><a href='#L439'>439</a>
505
+ <a name='L440'></a><a href='#L440'>440</a>
506
+ <a name='L441'></a><a href='#L441'>441</a>
507
+ <a name='L442'></a><a href='#L442'>442</a>
508
+ <a name='L443'></a><a href='#L443'>443</a>
509
+ <a name='L444'></a><a href='#L444'>444</a>
510
+ <a name='L445'></a><a href='#L445'>445</a>
511
+ <a name='L446'></a><a href='#L446'>446</a>
512
+ <a name='L447'></a><a href='#L447'>447</a>
513
+ <a name='L448'></a><a href='#L448'>448</a>
514
+ <a name='L449'></a><a href='#L449'>449</a>
515
+ <a name='L450'></a><a href='#L450'>450</a>
516
+ <a name='L451'></a><a href='#L451'>451</a>
517
+ <a name='L452'></a><a href='#L452'>452</a>
518
+ <a name='L453'></a><a href='#L453'>453</a>
519
+ <a name='L454'></a><a href='#L454'>454</a>
520
+ <a name='L455'></a><a href='#L455'>455</a>
521
+ <a name='L456'></a><a href='#L456'>456</a>
522
+ <a name='L457'></a><a href='#L457'>457</a>
523
+ <a name='L458'></a><a href='#L458'>458</a>
524
+ <a name='L459'></a><a href='#L459'>459</a>
525
+ <a name='L460'></a><a href='#L460'>460</a>
526
+ <a name='L461'></a><a href='#L461'>461</a>
527
+ <a name='L462'></a><a href='#L462'>462</a>
528
+ <a name='L463'></a><a href='#L463'>463</a>
529
+ <a name='L464'></a><a href='#L464'>464</a>
530
+ <a name='L465'></a><a href='#L465'>465</a>
531
+ <a name='L466'></a><a href='#L466'>466</a>
532
+ <a name='L467'></a><a href='#L467'>467</a>
533
+ <a name='L468'></a><a href='#L468'>468</a>
534
+ <a name='L469'></a><a href='#L469'>469</a>
535
+ <a name='L470'></a><a href='#L470'>470</a>
536
+ <a name='L471'></a><a href='#L471'>471</a>
537
+ <a name='L472'></a><a href='#L472'>472</a>
538
+ <a name='L473'></a><a href='#L473'>473</a>
539
+ <a name='L474'></a><a href='#L474'>474</a>
540
+ <a name='L475'></a><a href='#L475'>475</a>
541
+ <a name='L476'></a><a href='#L476'>476</a>
542
+ <a name='L477'></a><a href='#L477'>477</a>
543
+ <a name='L478'></a><a href='#L478'>478</a>
544
+ <a name='L479'></a><a href='#L479'>479</a>
545
+ <a name='L480'></a><a href='#L480'>480</a>
546
+ <a name='L481'></a><a href='#L481'>481</a>
547
+ <a name='L482'></a><a href='#L482'>482</a>
548
+ <a name='L483'></a><a href='#L483'>483</a>
549
+ <a name='L484'></a><a href='#L484'>484</a>
550
+ <a name='L485'></a><a href='#L485'>485</a>
551
+ <a name='L486'></a><a href='#L486'>486</a>
552
+ <a name='L487'></a><a href='#L487'>487</a>
553
+ <a name='L488'></a><a href='#L488'>488</a>
554
+ <a name='L489'></a><a href='#L489'>489</a>
555
+ <a name='L490'></a><a href='#L490'>490</a>
556
+ <a name='L491'></a><a href='#L491'>491</a>
557
+ <a name='L492'></a><a href='#L492'>492</a>
558
+ <a name='L493'></a><a href='#L493'>493</a>
559
+ <a name='L494'></a><a href='#L494'>494</a>
560
+ <a name='L495'></a><a href='#L495'>495</a>
561
+ <a name='L496'></a><a href='#L496'>496</a>
562
+ <a name='L497'></a><a href='#L497'>497</a>
563
+ <a name='L498'></a><a href='#L498'>498</a>
564
+ <a name='L499'></a><a href='#L499'>499</a>
565
+ <a name='L500'></a><a href='#L500'>500</a>
566
+ <a name='L501'></a><a href='#L501'>501</a>
567
+ <a name='L502'></a><a href='#L502'>502</a>
568
+ <a name='L503'></a><a href='#L503'>503</a>
569
+ <a name='L504'></a><a href='#L504'>504</a>
570
+ <a name='L505'></a><a href='#L505'>505</a>
571
+ <a name='L506'></a><a href='#L506'>506</a>
572
+ <a name='L507'></a><a href='#L507'>507</a>
573
+ <a name='L508'></a><a href='#L508'>508</a>
574
+ <a name='L509'></a><a href='#L509'>509</a>
575
+ <a name='L510'></a><a href='#L510'>510</a>
576
+ <a name='L511'></a><a href='#L511'>511</a>
577
+ <a name='L512'></a><a href='#L512'>512</a>
578
+ <a name='L513'></a><a href='#L513'>513</a>
579
+ <a name='L514'></a><a href='#L514'>514</a>
580
+ <a name='L515'></a><a href='#L515'>515</a>
581
+ <a name='L516'></a><a href='#L516'>516</a>
582
+ <a name='L517'></a><a href='#L517'>517</a>
583
+ <a name='L518'></a><a href='#L518'>518</a>
584
+ <a name='L519'></a><a href='#L519'>519</a>
585
+ <a name='L520'></a><a href='#L520'>520</a>
586
+ <a name='L521'></a><a href='#L521'>521</a></td><td class="line-coverage quiet"><span class="cline-any cline-yes">1x</span>
587
+ <span class="cline-any cline-yes">1x</span>
588
+ <span class="cline-any cline-yes">1x</span>
589
+ <span class="cline-any cline-yes">1x</span>
590
+ <span class="cline-any cline-yes">1x</span>
591
+ <span class="cline-any cline-yes">1x</span>
592
+ <span class="cline-any cline-yes">1x</span>
593
+ <span class="cline-any cline-yes">1x</span>
594
+ <span class="cline-any cline-yes">1x</span>
595
+ <span class="cline-any cline-yes">1x</span>
596
+ <span class="cline-any cline-yes">1x</span>
597
+ <span class="cline-any cline-yes">1x</span>
598
+ <span class="cline-any cline-yes">1x</span>
599
+ <span class="cline-any cline-yes">1x</span>
600
+ <span class="cline-any cline-yes">1x</span>
601
+ <span class="cline-any cline-yes">1x</span>
602
+ <span class="cline-any cline-yes">1x</span>
603
+ <span class="cline-any cline-yes">1x</span>
604
+ <span class="cline-any cline-yes">1x</span>
605
+ <span class="cline-any cline-yes">1x</span>
606
+ <span class="cline-any cline-yes">1x</span>
607
+ <span class="cline-any cline-yes">1x</span>
608
+ <span class="cline-any cline-yes">1x</span>
609
+ <span class="cline-any cline-yes">1x</span>
610
+ <span class="cline-any cline-yes">1x</span>
611
+ <span class="cline-any cline-yes">1x</span>
612
+ <span class="cline-any cline-yes">1x</span>
613
+ <span class="cline-any cline-yes">1x</span>
614
+ <span class="cline-any cline-yes">1x</span>
615
+ <span class="cline-any cline-yes">1x</span>
616
+ <span class="cline-any cline-yes">1x</span>
617
+ <span class="cline-any cline-yes">1x</span>
618
+ <span class="cline-any cline-yes">1x</span>
619
+ <span class="cline-any cline-yes">1x</span>
620
+ <span class="cline-any cline-yes">1x</span>
621
+ <span class="cline-any cline-yes">1x</span>
622
+ <span class="cline-any cline-yes">1x</span>
623
+ <span class="cline-any cline-yes">1x</span>
624
+ <span class="cline-any cline-yes">1x</span>
625
+ <span class="cline-any cline-yes">1x</span>
626
+ <span class="cline-any cline-yes">1x</span>
627
+ <span class="cline-any cline-yes">1x</span>
628
+ <span class="cline-any cline-yes">1x</span>
629
+ <span class="cline-any cline-yes">1x</span>
630
+ <span class="cline-any cline-yes">1x</span>
631
+ <span class="cline-any cline-yes">1x</span>
632
+ <span class="cline-any cline-yes">1x</span>
633
+ <span class="cline-any cline-yes">1x</span>
634
+ <span class="cline-any cline-yes">9x</span>
635
+ <span class="cline-any cline-yes">1x</span>
636
+ <span class="cline-any cline-yes">1x</span>
637
+ <span class="cline-any cline-yes">1x</span>
638
+ <span class="cline-any cline-yes">9x</span>
639
+ <span class="cline-any cline-yes">9x</span>
640
+ <span class="cline-any cline-yes">9x</span>
641
+ <span class="cline-any cline-yes">9x</span>
642
+ <span class="cline-any cline-yes">9x</span>
643
+ <span class="cline-any cline-yes">9x</span>
644
+ <span class="cline-any cline-yes">9x</span>
645
+ <span class="cline-any cline-yes">9x</span>
646
+ <span class="cline-any cline-yes">1x</span>
647
+ <span class="cline-any cline-yes">1x</span>
648
+ <span class="cline-any cline-yes">1x</span>
649
+ <span class="cline-any cline-yes">1x</span>
650
+ <span class="cline-any cline-yes">1x</span>
651
+ <span class="cline-any cline-yes">1x</span>
652
+ <span class="cline-any cline-yes">1x</span>
653
+ <span class="cline-any cline-yes">1x</span>
654
+ <span class="cline-any cline-yes">1x</span>
655
+ <span class="cline-any cline-yes">1x</span>
656
+ <span class="cline-any cline-yes">1x</span>
657
+ <span class="cline-any cline-yes">1x</span>
658
+ <span class="cline-any cline-yes">1x</span>
659
+ <span class="cline-any cline-yes">1x</span>
660
+ <span class="cline-any cline-yes">1x</span>
661
+ <span class="cline-any cline-yes">1x</span>
662
+ <span class="cline-any cline-yes">6x</span>
663
+ <span class="cline-any cline-yes">6x</span>
664
+ <span class="cline-any cline-yes">6x</span>
665
+ <span class="cline-any cline-yes">6x</span>
666
+ <span class="cline-any cline-yes">6x</span>
667
+ <span class="cline-any cline-yes">6x</span>
668
+ <span class="cline-any cline-yes">6x</span>
669
+ <span class="cline-any cline-yes">6x</span>
670
+ <span class="cline-any cline-yes">6x</span>
671
+ <span class="cline-any cline-yes">6x</span>
672
+ <span class="cline-any cline-yes">6x</span>
673
+ <span class="cline-any cline-yes">6x</span>
674
+ <span class="cline-any cline-yes">6x</span>
675
+ <span class="cline-any cline-yes">6x</span>
676
+ <span class="cline-any cline-yes">6x</span>
677
+ <span class="cline-any cline-yes">6x</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-no">&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-yes">6x</span>
686
+ <span class="cline-any cline-yes">6x</span>
687
+ <span class="cline-any cline-yes">6x</span>
688
+ <span class="cline-any cline-yes">6x</span>
689
+ <span class="cline-any cline-yes">6x</span>
690
+ <span class="cline-any cline-yes">6x</span>
691
+ <span class="cline-any cline-yes">6x</span>
692
+ <span class="cline-any cline-yes">6x</span>
693
+ <span class="cline-any cline-yes">6x</span>
694
+ <span class="cline-any cline-yes">6x</span>
695
+ <span class="cline-any cline-yes">6x</span>
696
+ <span class="cline-any cline-yes">6x</span>
697
+ <span class="cline-any cline-yes">6x</span>
698
+ <span class="cline-any cline-yes">6x</span>
699
+ <span class="cline-any cline-yes">6x</span>
700
+ <span class="cline-any cline-yes">6x</span>
701
+ <span class="cline-any cline-yes">6x</span>
702
+ <span class="cline-any cline-yes">6x</span>
703
+ <span class="cline-any cline-yes">6x</span>
704
+ <span class="cline-any cline-yes">6x</span>
705
+ <span class="cline-any cline-yes">6x</span>
706
+ <span class="cline-any cline-yes">6x</span>
707
+ <span class="cline-any cline-yes">6x</span>
708
+ <span class="cline-any cline-yes">6x</span>
709
+ <span class="cline-any cline-yes">6x</span>
710
+ <span class="cline-any cline-yes">6x</span>
711
+ <span class="cline-any cline-yes">6x</span>
712
+ <span class="cline-any cline-yes">6x</span>
713
+ <span class="cline-any cline-yes">6x</span>
714
+ <span class="cline-any cline-yes">6x</span>
715
+ <span class="cline-any cline-yes">6x</span>
716
+ <span class="cline-any cline-yes">6x</span>
717
+ <span class="cline-any cline-yes">6x</span>
718
+ <span class="cline-any cline-yes">6x</span>
719
+ <span class="cline-any cline-yes">12x</span>
720
+ <span class="cline-any cline-yes">12x</span>
721
+ <span class="cline-any cline-yes">12x</span>
722
+ <span class="cline-any cline-yes">12x</span>
723
+ <span class="cline-any cline-yes">12x</span>
724
+ <span class="cline-any cline-yes">12x</span>
725
+ <span class="cline-any cline-yes">6x</span>
726
+ <span class="cline-any cline-yes">6x</span>
727
+ <span class="cline-any cline-yes">6x</span>
728
+ <span class="cline-any cline-yes">6x</span>
729
+ <span class="cline-any cline-yes">6x</span>
730
+ <span class="cline-any cline-yes">6x</span>
731
+ <span class="cline-any cline-yes">6x</span>
732
+ <span class="cline-any cline-yes">6x</span>
733
+ <span class="cline-any cline-yes">6x</span>
734
+ <span class="cline-any cline-yes">6x</span>
735
+ <span class="cline-any cline-yes">6x</span>
736
+ <span class="cline-any cline-yes">6x</span>
737
+ <span class="cline-any cline-yes">6x</span>
738
+ <span class="cline-any cline-yes">6x</span>
739
+ <span class="cline-any cline-yes">6x</span>
740
+ <span class="cline-any cline-yes">6x</span>
741
+ <span class="cline-any cline-yes">6x</span>
742
+ <span class="cline-any cline-yes">6x</span>
743
+ <span class="cline-any cline-yes">6x</span>
744
+ <span class="cline-any cline-yes">6x</span>
745
+ <span class="cline-any cline-yes">6x</span>
746
+ <span class="cline-any cline-yes">6x</span>
747
+ <span class="cline-any cline-yes">6x</span>
748
+ <span class="cline-any cline-yes">6x</span>
749
+ <span class="cline-any cline-yes">6x</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-no">&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-no">&nbsp;</span>
757
+ <span class="cline-any cline-yes">519x</span>
758
+ <span class="cline-any cline-yes">6x</span>
759
+ <span class="cline-any cline-yes">6x</span>
760
+ <span class="cline-any cline-yes">6x</span>
761
+ <span class="cline-any cline-yes">6x</span>
762
+ <span class="cline-any cline-yes">6x</span>
763
+ <span class="cline-any cline-yes">6x</span>
764
+ <span class="cline-any cline-yes">260x</span>
765
+ <span class="cline-any cline-yes">260x</span>
766
+ <span class="cline-any cline-yes">260x</span>
767
+ <span class="cline-any cline-yes">260x</span>
768
+ <span class="cline-any cline-yes">260x</span>
769
+ <span class="cline-any cline-yes">254x</span>
770
+ <span class="cline-any cline-yes">254x</span>
771
+ <span class="cline-any cline-yes">254x</span>
772
+ <span class="cline-any cline-yes">254x</span>
773
+ <span class="cline-any cline-yes">254x</span>
774
+ <span class="cline-any cline-no">&nbsp;</span>
775
+ <span class="cline-any cline-yes">254x</span>
776
+ <span class="cline-any cline-yes">254x</span>
777
+ <span class="cline-any cline-yes">254x</span>
778
+ <span class="cline-any cline-yes">260x</span>
779
+ <span class="cline-any cline-yes">6x</span>
780
+ <span class="cline-any cline-yes">6x</span>
781
+ <span class="cline-any cline-yes">6x</span>
782
+ <span class="cline-any cline-yes">6x</span>
783
+ <span class="cline-any cline-yes">6x</span>
784
+ <span class="cline-any cline-yes">6x</span>
785
+ <span class="cline-any cline-yes">6x</span>
786
+ <span class="cline-any cline-yes">6x</span>
787
+ <span class="cline-any cline-yes">260x</span>
788
+ <span class="cline-any cline-yes">260x</span>
789
+ <span class="cline-any cline-yes">260x</span>
790
+ <span class="cline-any cline-yes">1x</span>
791
+ <span class="cline-any cline-yes">1x</span>
792
+ <span class="cline-any cline-yes">1x</span>
793
+ <span class="cline-any cline-yes">1x</span>
794
+ <span class="cline-any cline-yes">259x</span>
795
+ <span class="cline-any cline-yes">259x</span>
796
+ <span class="cline-any cline-yes">259x</span>
797
+ <span class="cline-any cline-yes">259x</span>
798
+ <span class="cline-any cline-yes">259x</span>
799
+ <span class="cline-any cline-yes">259x</span>
800
+ <span class="cline-any cline-yes">259x</span>
801
+ <span class="cline-any cline-yes">259x</span>
802
+ <span class="cline-any cline-yes">5x</span>
803
+ <span class="cline-any cline-yes">5x</span>
804
+ <span class="cline-any cline-yes">5x</span>
805
+ <span class="cline-any cline-yes">5x</span>
806
+ <span class="cline-any cline-yes">259x</span>
807
+ <span class="cline-any cline-yes">6x</span>
808
+ <span class="cline-any cline-yes">6x</span>
809
+ <span class="cline-any cline-yes">6x</span>
810
+ <span class="cline-any cline-yes">6x</span>
811
+ <span class="cline-any cline-yes">6x</span>
812
+ <span class="cline-any cline-yes">6x</span>
813
+ <span class="cline-any cline-yes">6x</span>
814
+ <span class="cline-any cline-yes">6x</span>
815
+ <span class="cline-any cline-yes">6x</span>
816
+ <span class="cline-any cline-yes">6x</span>
817
+ <span class="cline-any cline-yes">6x</span>
818
+ <span class="cline-any cline-yes">6x</span>
819
+ <span class="cline-any cline-yes">6x</span>
820
+ <span class="cline-any cline-yes">6x</span>
821
+ <span class="cline-any cline-yes">6x</span>
822
+ <span class="cline-any cline-yes">6x</span>
823
+ <span class="cline-any cline-yes">6x</span>
824
+ <span class="cline-any cline-yes">6x</span>
825
+ <span class="cline-any cline-yes">6x</span>
826
+ <span class="cline-any cline-yes">6x</span>
827
+ <span class="cline-any cline-yes">6x</span>
828
+ <span class="cline-any cline-yes">6x</span>
829
+ <span class="cline-any cline-yes">6x</span>
830
+ <span class="cline-any cline-yes">6x</span>
831
+ <span class="cline-any cline-yes">6x</span>
832
+ <span class="cline-any cline-yes">6x</span>
833
+ <span class="cline-any cline-yes">6x</span>
834
+ <span class="cline-any cline-yes">6x</span>
835
+ <span class="cline-any cline-yes">6x</span>
836
+ <span class="cline-any cline-yes">6x</span>
837
+ <span class="cline-any cline-yes">6x</span>
838
+ <span class="cline-any cline-yes">6x</span>
839
+ <span class="cline-any cline-yes">6x</span>
840
+ <span class="cline-any cline-yes">6x</span>
841
+ <span class="cline-any cline-yes">6x</span>
842
+ <span class="cline-any cline-yes">6x</span>
843
+ <span class="cline-any cline-yes">6x</span>
844
+ <span class="cline-any cline-yes">6x</span>
845
+ <span class="cline-any cline-yes">6x</span>
846
+ <span class="cline-any cline-yes">6x</span>
847
+ <span class="cline-any cline-yes">6x</span>
848
+ <span class="cline-any cline-yes">6x</span>
849
+ <span class="cline-any cline-yes">5x</span>
850
+ <span class="cline-any cline-yes">5x</span>
851
+ <span class="cline-any cline-no">&nbsp;</span>
852
+ <span class="cline-any cline-no">&nbsp;</span>
853
+ <span class="cline-any cline-no">&nbsp;</span>
854
+ <span class="cline-any cline-yes">6x</span>
855
+ <span class="cline-any cline-yes">1x</span>
856
+ <span class="cline-any cline-yes">1x</span>
857
+ <span class="cline-any cline-yes">1x</span>
858
+ <span class="cline-any cline-yes">1x</span>
859
+ <span class="cline-any cline-yes">1x</span>
860
+ <span class="cline-any cline-yes">1x</span>
861
+ <span class="cline-any cline-yes">1x</span>
862
+ <span class="cline-any cline-yes">6x</span>
863
+ <span class="cline-any cline-yes">6x</span>
864
+ <span class="cline-any cline-yes">6x</span>
865
+ <span class="cline-any cline-yes">6x</span>
866
+ <span class="cline-any cline-yes">6x</span>
867
+ <span class="cline-any cline-yes">6x</span>
868
+ <span class="cline-any cline-yes">6x</span>
869
+ <span class="cline-any cline-yes">6x</span>
870
+ <span class="cline-any cline-yes">6x</span>
871
+ <span class="cline-any cline-yes">6x</span>
872
+ <span class="cline-any cline-yes">6x</span>
873
+ <span class="cline-any cline-yes">6x</span>
874
+ <span class="cline-any cline-yes">6x</span>
875
+ <span class="cline-any cline-yes">6x</span>
876
+ <span class="cline-any cline-yes">6x</span>
877
+ <span class="cline-any cline-yes">6x</span>
878
+ <span class="cline-any cline-yes">6x</span>
879
+ <span class="cline-any cline-yes">1x</span>
880
+ <span class="cline-any cline-yes">1x</span>
881
+ <span class="cline-any cline-yes">1x</span>
882
+ <span class="cline-any cline-yes">1x</span>
883
+ <span class="cline-any cline-yes">1x</span>
884
+ <span class="cline-any cline-yes">1x</span>
885
+ <span class="cline-any cline-yes">1x</span>
886
+ <span class="cline-any cline-yes">1x</span>
887
+ <span class="cline-any cline-yes">1x</span>
888
+ <span class="cline-any cline-yes">1x</span>
889
+ <span class="cline-any cline-yes">1x</span>
890
+ <span class="cline-any cline-yes">1x</span>
891
+ <span class="cline-any cline-yes">1x</span>
892
+ <span class="cline-any cline-yes">1x</span>
893
+ <span class="cline-any cline-yes">1x</span>
894
+ <span class="cline-any cline-yes">1x</span>
895
+ <span class="cline-any cline-yes">1x</span>
896
+ <span class="cline-any cline-yes">1x</span>
897
+ <span class="cline-any cline-yes">6x</span>
898
+ <span class="cline-any cline-yes">6x</span>
899
+ <span class="cline-any cline-yes">6x</span>
900
+ <span class="cline-any cline-yes">6x</span>
901
+ <span class="cline-any cline-yes">6x</span>
902
+ <span class="cline-any cline-yes">6x</span>
903
+ <span class="cline-any cline-yes">6x</span>
904
+ <span class="cline-any cline-yes">6x</span>
905
+ <span class="cline-any cline-yes">6x</span>
906
+ <span class="cline-any cline-yes">6x</span>
907
+ <span class="cline-any cline-yes">6x</span>
908
+ <span class="cline-any cline-yes">6x</span>
909
+ <span class="cline-any cline-yes">6x</span>
910
+ <span class="cline-any cline-yes">6x</span>
911
+ <span class="cline-any cline-yes">6x</span>
912
+ <span class="cline-any cline-yes">6x</span>
913
+ <span class="cline-any cline-yes">6x</span>
914
+ <span class="cline-any cline-yes">6x</span>
915
+ <span class="cline-any cline-yes">1x</span>
916
+ <span class="cline-any cline-yes">1x</span>
917
+ <span class="cline-any cline-yes">1x</span>
918
+ <span class="cline-any cline-yes">1x</span>
919
+ <span class="cline-any cline-yes">1x</span>
920
+ <span class="cline-any cline-yes">1x</span>
921
+ <span class="cline-any cline-yes">1x</span>
922
+ <span class="cline-any cline-yes">1x</span>
923
+ <span class="cline-any cline-yes">5x</span>
924
+ <span class="cline-any cline-yes">5x</span>
925
+ <span class="cline-any cline-yes">5x</span>
926
+ <span class="cline-any cline-yes">5x</span>
927
+ <span class="cline-any cline-yes">5x</span>
928
+ <span class="cline-any cline-yes">5x</span>
929
+ <span class="cline-any cline-yes">6x</span>
930
+ <span class="cline-any cline-yes">6x</span>
931
+ <span class="cline-any cline-yes">6x</span>
932
+ <span class="cline-any cline-yes">6x</span>
933
+ <span class="cline-any cline-yes">6x</span>
934
+ <span class="cline-any cline-yes">6x</span>
935
+ <span class="cline-any cline-yes">6x</span>
936
+ <span class="cline-any cline-yes">6x</span>
937
+ <span class="cline-any cline-yes">6x</span>
938
+ <span class="cline-any cline-yes">6x</span>
939
+ <span class="cline-any cline-yes">6x</span>
940
+ <span class="cline-any cline-yes">6x</span>
941
+ <span class="cline-any cline-yes">6x</span>
942
+ <span class="cline-any cline-yes">6x</span>
943
+ <span class="cline-any cline-yes">6x</span>
944
+ <span class="cline-any cline-yes">6x</span>
945
+ <span class="cline-any cline-yes">6x</span>
946
+ <span class="cline-any cline-yes">6x</span>
947
+ <span class="cline-any cline-yes">6x</span>
948
+ <span class="cline-any cline-yes">6x</span>
949
+ <span class="cline-any cline-yes">6x</span>
950
+ <span class="cline-any cline-yes">6x</span>
951
+ <span class="cline-any cline-yes">6x</span>
952
+ <span class="cline-any cline-yes">6x</span>
953
+ <span class="cline-any cline-yes">3x</span>
954
+ <span class="cline-any cline-yes">3x</span>
955
+ <span class="cline-any cline-yes">1x</span>
956
+ <span class="cline-any cline-yes">1x</span>
957
+ <span class="cline-any cline-yes">3x</span>
958
+ <span class="cline-any cline-yes">3x</span>
959
+ <span class="cline-any cline-yes">6x</span>
960
+ <span class="cline-any cline-yes">6x</span>
961
+ <span class="cline-any cline-yes">6x</span>
962
+ <span class="cline-any cline-yes">6x</span>
963
+ <span class="cline-any cline-no">&nbsp;</span>
964
+ <span class="cline-any cline-no">&nbsp;</span>
965
+ <span class="cline-any cline-no">&nbsp;</span>
966
+ <span class="cline-any cline-yes">519x</span>
967
+ <span class="cline-any cline-yes">6x</span>
968
+ <span class="cline-any cline-yes">6x</span>
969
+ <span class="cline-any cline-yes">6x</span>
970
+ <span class="cline-any cline-yes">6x</span>
971
+ <span class="cline-any cline-yes">6x</span>
972
+ <span class="cline-any cline-yes">6x</span>
973
+ <span class="cline-any cline-yes">6x</span>
974
+ <span class="cline-any cline-yes">6x</span>
975
+ <span class="cline-any cline-yes">6x</span>
976
+ <span class="cline-any cline-yes">6x</span>
977
+ <span class="cline-any cline-yes">6x</span>
978
+ <span class="cline-any cline-yes">6x</span>
979
+ <span class="cline-any cline-yes">6x</span>
980
+ <span class="cline-any cline-yes">6x</span>
981
+ <span class="cline-any cline-yes">6x</span>
982
+ <span class="cline-any cline-yes">6x</span>
983
+ <span class="cline-any cline-yes">6x</span>
984
+ <span class="cline-any cline-yes">6x</span>
985
+ <span class="cline-any cline-yes">6x</span>
986
+ <span class="cline-any cline-yes">6x</span>
987
+ <span class="cline-any cline-yes">6x</span>
988
+ <span class="cline-any cline-yes">6x</span>
989
+ <span class="cline-any cline-yes">6x</span>
990
+ <span class="cline-any cline-yes">6x</span>
991
+ <span class="cline-any cline-yes">6x</span>
992
+ <span class="cline-any cline-yes">6x</span>
993
+ <span class="cline-any cline-yes">6x</span>
994
+ <span class="cline-any cline-yes">6x</span>
995
+ <span class="cline-any cline-yes">6x</span>
996
+ <span class="cline-any cline-yes">6x</span>
997
+ <span class="cline-any cline-yes">6x</span>
998
+ <span class="cline-any cline-yes">6x</span>
999
+ <span class="cline-any cline-yes">6x</span>
1000
+ <span class="cline-any cline-yes">6x</span>
1001
+ <span class="cline-any cline-yes">6x</span>
1002
+ <span class="cline-any cline-yes">6x</span>
1003
+ <span class="cline-any cline-yes">6x</span>
1004
+ <span class="cline-any cline-yes">6x</span>
1005
+ <span class="cline-any cline-yes">6x</span>
1006
+ <span class="cline-any cline-yes">6x</span>
1007
+ <span class="cline-any cline-yes">6x</span>
1008
+ <span class="cline-any cline-yes">6x</span>
1009
+ <span class="cline-any cline-yes">6x</span>
1010
+ <span class="cline-any cline-yes">6x</span>
1011
+ <span class="cline-any cline-yes">6x</span>
1012
+ <span class="cline-any cline-yes">6x</span>
1013
+ <span class="cline-any cline-yes">6x</span>
1014
+ <span class="cline-any cline-yes">6x</span>
1015
+ <span class="cline-any cline-yes">6x</span>
1016
+ <span class="cline-any cline-no">&nbsp;</span>
1017
+ <span class="cline-any cline-yes">6x</span>
1018
+ <span class="cline-any cline-yes">6x</span>
1019
+ <span class="cline-any cline-yes">6x</span>
1020
+ <span class="cline-any cline-yes">6x</span>
1021
+ <span class="cline-any cline-yes">6x</span>
1022
+ <span class="cline-any cline-yes">5x</span>
1023
+ <span class="cline-any cline-no">&nbsp;</span>
1024
+ <span class="cline-any cline-no">&nbsp;</span>
1025
+ <span class="cline-any cline-no">&nbsp;</span>
1026
+ <span class="cline-any cline-no">&nbsp;</span>
1027
+ <span class="cline-any cline-yes">5x</span>
1028
+ <span class="cline-any cline-yes">5x</span>
1029
+ <span class="cline-any cline-yes">5x</span>
1030
+ <span class="cline-any cline-yes">5x</span>
1031
+ <span class="cline-any cline-yes">6x</span>
1032
+ <span class="cline-any cline-yes">6x</span>
1033
+ <span class="cline-any cline-yes">6x</span>
1034
+ <span class="cline-any cline-yes">6x</span>
1035
+ <span class="cline-any cline-yes">6x</span>
1036
+ <span class="cline-any cline-yes">6x</span>
1037
+ <span class="cline-any cline-yes">6x</span>
1038
+ <span class="cline-any cline-yes">6x</span>
1039
+ <span class="cline-any cline-yes">6x</span>
1040
+ <span class="cline-any cline-yes">6x</span>
1041
+ <span class="cline-any cline-yes">6x</span>
1042
+ <span class="cline-any cline-yes">254x</span>
1043
+ <span class="cline-any cline-yes">254x</span>
1044
+ <span class="cline-any cline-yes">6x</span>
1045
+ <span class="cline-any cline-yes">6x</span>
1046
+ <span class="cline-any cline-yes">6x</span>
1047
+ <span class="cline-any cline-yes">6x</span>
1048
+ <span class="cline-any cline-yes">6x</span>
1049
+ <span class="cline-any cline-yes">6x</span>
1050
+ <span class="cline-any cline-yes">6x</span>
1051
+ <span class="cline-any cline-yes">6x</span>
1052
+ <span class="cline-any cline-yes">6x</span>
1053
+ <span class="cline-any cline-yes">259x</span>
1054
+ <span class="cline-any cline-yes">259x</span>
1055
+ <span class="cline-any cline-yes">259x</span>
1056
+ <span class="cline-any cline-yes">259x</span>
1057
+ <span class="cline-any cline-yes">259x</span>
1058
+ <span class="cline-any cline-yes">259x</span>
1059
+ <span class="cline-any cline-yes">259x</span>
1060
+ <span class="cline-any cline-yes">259x</span>
1061
+ <span class="cline-any cline-yes">259x</span>
1062
+ <span class="cline-any cline-yes">259x</span>
1063
+ <span class="cline-any cline-yes">259x</span>
1064
+ <span class="cline-any cline-yes">259x</span>
1065
+ <span class="cline-any cline-yes">6x</span>
1066
+ <span class="cline-any cline-yes">6x</span>
1067
+ <span class="cline-any cline-yes">6x</span>
1068
+ <span class="cline-any cline-yes">6x</span>
1069
+ <span class="cline-any cline-yes">6x</span>
1070
+ <span class="cline-any cline-yes">3x</span>
1071
+ <span class="cline-any cline-yes">3x</span>
1072
+ <span class="cline-any cline-yes">3x</span>
1073
+ <span class="cline-any cline-yes">6x</span>
1074
+ <span class="cline-any cline-yes">6x</span>
1075
+ <span class="cline-any cline-yes">6x</span>
1076
+ <span class="cline-any cline-yes">5x</span>
1077
+ <span class="cline-any cline-yes">5x</span>
1078
+ <span class="cline-any cline-yes">5x</span>
1079
+ <span class="cline-any cline-yes">5x</span>
1080
+ <span class="cline-any cline-yes">5x</span>
1081
+ <span class="cline-any cline-yes">5x</span>
1082
+ <span class="cline-any cline-yes">5x</span>
1083
+ <span class="cline-any cline-yes">5x</span>
1084
+ <span class="cline-any cline-yes">6x</span>
1085
+ <span class="cline-any cline-yes">1x</span>
1086
+ <span class="cline-any cline-yes">1x</span>
1087
+ <span class="cline-any cline-yes">1x</span>
1088
+ <span class="cline-any cline-yes">1x</span>
1089
+ <span class="cline-any cline-yes">1x</span>
1090
+ <span class="cline-any cline-yes">1x</span>
1091
+ <span class="cline-any cline-yes">1x</span>
1092
+ <span class="cline-any cline-yes">1x</span>
1093
+ <span class="cline-any cline-yes">1x</span>
1094
+ <span class="cline-any cline-yes">1x</span>
1095
+ <span class="cline-any cline-yes">1x</span>
1096
+ <span class="cline-any cline-yes">1x</span>
1097
+ <span class="cline-any cline-yes">1x</span>
1098
+ <span class="cline-any cline-yes">1x</span>
1099
+ <span class="cline-any cline-yes">1x</span>
1100
+ <span class="cline-any cline-yes">1x</span>
1101
+ <span class="cline-any cline-yes">6x</span>
1102
+ <span class="cline-any cline-yes">6x</span>
1103
+ <span class="cline-any cline-yes">6x</span>
1104
+ <span class="cline-any cline-yes">6x</span>
1105
+ <span class="cline-any cline-no">&nbsp;</span>
1106
+ <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js"><span class="branch-0 cbranch-no" title="branch not covered" >/*</span>
1107
+ ** MQTT+ -- MQTT Communication Patterns
1108
+ ** Copyright (c) 2018-2026 Dr. Ralf S. Engelschall &lt;rse@engelschall.com&gt;
1109
+ **
1110
+ ** Permission is hereby granted, free of charge, to any person obtaining
1111
+ ** a copy of this software and associated documentation files (the
1112
+ ** "Software"), to deal in the Software without restriction, including
1113
+ ** without limitation the rights to use, copy, modify, merge, publish,
1114
+ ** distribute, sublicense, and/or sell copies of the Software, and to
1115
+ ** permit persons to whom the Software is furnished to do so, subject to
1116
+ ** the following conditions:
1117
+ **
1118
+ ** The above copyright notice and this permission notice shall be included
1119
+ ** in all copies or substantial portions of the Software.
1120
+ **
1121
+ ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1122
+ ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1123
+ ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
1124
+ ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
1125
+ ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
1126
+ ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
1127
+ ** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1128
+ */
1129
+ &nbsp;
1130
+ /* built-in requirements */
1131
+ import { Readable } from "node:stream"
1132
+ &nbsp;
1133
+ /* external requirements */
1134
+ import type { IClientPublishOptions,
1135
+ IClientSubscribeOptions } from "mqtt"
1136
+ import { nanoid } from "nanoid"
1137
+ &nbsp;
1138
+ /* internal requirements */
1139
+ import { CreditGate,
1140
+ streamToBuffer, sendBufferAsChunks,
1141
+ sendStreamAsChunks, makeMutuallyExclusiveFields } from "./mqtt-plus-util"
1142
+ import { run, Spool, ensureError } from "./mqtt-plus-error"
1143
+ import type { SinkPushRequest, SinkPushResponse,
1144
+ SinkPushChunk, SinkPushCredit } from "./mqtt-plus-msg"
1145
+ import type { APISchema, SinkKeys, Registration } from "./mqtt-plus-api"
1146
+ import type { WithInfo, InfoSink } from "./mqtt-plus-info"
1147
+ import { SourceTrait } from "./mqtt-plus-source"
1148
+ import type { AuthOption } from "./mqtt-plus-auth"
1149
+ &nbsp;
1150
+ /* Sink Push Trait */
1151
+ export class SinkTrait&lt;T extends APISchema = APISchema&gt; extends SourceTrait&lt;T&gt; {
1152
+ /* sink state */
1153
+ private pushStreams = new Map&lt;string, Readable&gt;()
1154
+ private pushSpools = new Map&lt;string, Spool&gt;()
1155
+ &nbsp;
1156
+ /* destroy trait */
1157
+ override async destroy () {
1158
+ for (const stream of this.pushStreams.values())
1159
+ <span class="branch-0 cbranch-no" title="branch not covered" > stream.destroy(new Error("sink destroyed"))</span>
1160
+ this.pushStreams.clear()
1161
+ for (const spool of this.pushSpools.values())
1162
+ <span class="branch-0 cbranch-no" title="branch not covered" > await spool.unroll()</span>
1163
+ this.pushSpools.clear()
1164
+ await super.destroy()
1165
+ }
1166
+ &nbsp;
1167
+ /* register a sink */
1168
+ async sink&lt;K extends SinkKeys&lt;T&gt; &amp; string&gt; (
1169
+ name: K,
1170
+ callback: WithInfo&lt;T[K], InfoSink&gt;
1171
+ ): Promise&lt;Registration&gt;
1172
+ async sink&lt;K extends SinkKeys&lt;T&gt; &amp; string&gt; (
1173
+ config: {
1174
+ name: K,
1175
+ callback: WithInfo&lt;T[K], InfoSink&gt;,
1176
+ options?: Partial&lt;IClientSubscribeOptions&gt;,
1177
+ share?: string,
1178
+ auth?: AuthOption
1179
+ }
1180
+ ): Promise&lt;Registration&gt;
1181
+ async sink&lt;K extends SinkKeys&lt;T&gt; &amp; string&gt; (
1182
+ nameOrConfig: K | {
1183
+ name: K,
1184
+ callback: WithInfo&lt;T[K], InfoSink&gt;,
1185
+ options?: Partial&lt;IClientSubscribeOptions&gt;,
1186
+ share?: string,
1187
+ auth?: AuthOption
1188
+ },
1189
+ ...args: any[]
1190
+ ): Promise&lt;Registration&gt; {
1191
+ /* determine actual parameters */
1192
+ let name: K
1193
+ let callback: WithInfo&lt;T[K], InfoSink&gt;
1194
+ let options: Partial&lt;IClientSubscribeOptions&gt; = {}
1195
+ let share = this.options.share
1196
+ let auth: AuthOption | undefined
1197
+ if (typeof nameOrConfig === <span class="branch-0 cbranch-no" title="branch not covered" >"object" &amp;&amp; nameOrConfig !== null) <span class="branch-0 cbranch-no" title="branch not covered" >{</span></span>
1198
+ <span class="cstat-no" title="statement not covered" > /* object-based API */</span>
1199
+ <span class="cstat-no" title="statement not covered" > name = nameOrConfig.name</span>
1200
+ <span class="cstat-no" title="statement not covered" > callback = nameOrConfig.callback</span>
1201
+ <span class="cstat-no" title="statement not covered" > options = nameOrConfig.options ?? {}</span>
1202
+ <span class="cstat-no" title="statement not covered" > share = nameOrConfig.share ?? this.options.share</span>
1203
+ <span class="cstat-no" title="statement not covered" > auth = nameOrConfig.auth</span>
1204
+ <span class="cstat-no" title="statement not covered" > }</span>
1205
+ else {
1206
+ /* positional API */
1207
+ name = nameOrConfig
1208
+ callback = args[0]
1209
+ }
1210
+ &nbsp;
1211
+ /* create a resource spool */
1212
+ const spool = new Spool()
1213
+ &nbsp;
1214
+ /* sanity check situation */
1215
+ if (this.onRequest.has(`sink-push-request:${name}`))
1216
+ <span class="branch-0 cbranch-no" title="branch not covered" > throw new Error(`sink: sink "${name}" already registered`)</span>
1217
+ &nbsp;
1218
+ /* generate the corresponding MQTT topics for broadcast and direct use */
1219
+ const topicS = share !== "" ? `$share/${share}/${name<span class="branch-0 cbranch-no" title="branch not covered" >}` : name</span>
1220
+ const topicReqB = this.options.topicMake(topicS, "sink-push-request")
1221
+ const topicReqD = this.options.topicMake(name, "sink-push-request", this.options.id)
1222
+ &nbsp;
1223
+ /* react on sink push request */
1224
+ this.onRequest.set(`sink-push-request:${name}`, async (request: SinkPushRequest, topicName: string) =&gt; {
1225
+ /* determine information */
1226
+ const requestId = request.id
1227
+ const params = request.<span class="branch-0 cbranch-no" title="branch not covered" >params ?? []</span>
1228
+ const sender = request.sender
1229
+ if (sender === undefined || sender === "")
1230
+ <span class="branch-0 cbranch-no" title="branch not covered" > throw new Error("invalid request: missing sender")</span>
1231
+ const receiver = request.receiver
1232
+ &nbsp;
1233
+ /* generate corresponding MQTT topic for response */
1234
+ const responseTopic = this.options.topicMake(name, "sink-push-response", sender)
1235
+ &nbsp;
1236
+ /* callback for sending the ack/nak response */
1237
+ const chunkCredit = this.options.chunkCredit
1238
+ const sendResponse = async (error?: string, withCredit: boolean = false) =&gt; {
1239
+ const credit = (error === undefined &amp;&amp; withCredit &amp;&amp; chunkCredit &gt; 0) ? chunkCredit : undefined
1240
+ const response = this.msg.makeSinkPushResponse(requestId,
1241
+ name, error, this.options.id, sender, credit)
1242
+ const message = this.codec.encode(response)
1243
+ await this.publishToTopic(responseTopic, message, { qos: options.qos ?? 2 })
1244
+ }
1245
+ &nbsp;
1246
+ /* create a resource spool for stream cleanup */
1247
+ const reqSpool = new Spool()
1248
+ this.pushSpools.set(requestId, reqSpool)
1249
+ reqSpool.roll(() =&gt; { this.pushSpools.delete(requestId) })
1250
+ &nbsp;
1251
+ /* check authentication and prepare stream */
1252
+ try {
1253
+ if (topicName !== request.name)
1254
+ <span class="branch-0 cbranch-no" title="branch not covered" > throw new Error(`sink name mismatch (topic: "${topicName}", payload: "${request.name}")`)</span>
1255
+ let authenticated: boolean | undefined = undefined
1256
+ if (auth)
1257
+ <span class="branch-0 cbranch-no" title="branch not covered" > authenticated = await this.authenticated(sender, request.auth, auth)</span>
1258
+ if (authenticated !== <span class="branch-0 cbranch-no" title="branch not covered" >undefined &amp;&amp; !authenticated)</span>
1259
+ <span class="branch-0 cbranch-no" title="branch not covered" > throw new Error(`sink "${name}" failed authentication`)</span>
1260
+ &nbsp;
1261
+ /* initialize credit-based flow control state */
1262
+ const creditState = chunkCredit &gt; 0 ? {
1263
+ chunksReceived: 0,
1264
+ creditGranted: chunkCredit
1265
+ <span class="branch-0 cbranch-no" title="branch not covered" > } : undefined</span>
1266
+ &nbsp;
1267
+ /* utility functions for timeout management */
1268
+ const pushTimerId = `sink-push-recv:${requestId}`
1269
+ const refreshPushTimeout = () =&gt; this.timerRefresh(pushTimerId, () =&gt; {
1270
+ <span class="cstat-no" title="statement not covered" > if (streamEnded)</span>
1271
+ <span class="cstat-no" title="statement not covered" > return</span>
1272
+ <span class="cstat-no" title="statement not covered" > const stream = this.pushStreams.get(requestId)</span>
1273
+ <span class="cstat-no" title="statement not covered" > if (stream !== undefined)</span>
1274
+ <span class="cstat-no" title="statement not covered" > stream.destroy(new Error("push stream timeout"))</span>
1275
+ <span class="cstat-no" title="statement not covered" > const spool = this.pushSpools.get(requestId)</span>
1276
+ <span class="cstat-no" title="statement not covered" > spool?.unroll()</span>
1277
+ })
1278
+ const clearPushTimeout = () =&gt; this.timerClear(pushTimerId)
1279
+ &nbsp;
1280
+ /* create a readable for buffering received chunks */
1281
+ const readable = new Readable({
1282
+ highWaterMark: chunkCredit &gt; 0 ? chunkCredit * this.options.<span class="branch-0 cbranch-no" title="branch not covered" >chunkSize : 16 * 1024,</span>
1283
+ read: (_size) =&gt; {
1284
+ if (!creditState || !this.pushSpools.has(requestId))
1285
+ <span class="branch-0 cbranch-no" title="branch not covered" > return</span>
1286
+ const creditToGrant = Math.max(0,
1287
+ creditState.chunksReceived + chunkCredit - creditState.creditGranted)
1288
+ if (creditToGrant &gt; 0) {
1289
+ creditState.creditGranted += creditToGrant
1290
+ const creditMsg = this.msg.makeSinkPushCredit(requestId,
1291
+ name, creditToGrant, this.options.id, sender)
1292
+ const encoded = this.codec.encode(creditMsg)
1293
+ this.publishToTopic(responseTopic, encoded, { qos: options.qos ?? 2 }).catch((err: Error) =&gt; {
1294
+ <span class="cstat-no" title="statement not covered" > this.error(err, `sending credit for push "${name}" failed`)</span>
1295
+ })
1296
+ refreshPushTimeout()
1297
+ }
1298
+ }
1299
+ })
1300
+ this.pushStreams.set(requestId, readable)
1301
+ reqSpool.roll(() =&gt; { this.pushStreams.delete(requestId) })
1302
+ readable.once("error", () =&gt; {}) /* prevent unhandled error exception */
1303
+ &nbsp;
1304
+ /* register chunk dispatch callback */
1305
+ let streamEnded = false
1306
+ this.onResponse.set(`sink-push-chunk:${requestId}`, async (chunkParsed: SinkPushChunk) =&gt; {
1307
+ if (streamEnded)
1308
+ <span class="branch-0 cbranch-no" title="branch not covered" > return</span>
1309
+ if (chunkParsed.error !== undefined) {
1310
+ streamEnded = true
1311
+ clearPushTimeout()
1312
+ readable.destroy(new Error(chunkParsed.error))
1313
+ }
1314
+ else {
1315
+ refreshPushTimeout()
1316
+ if (chunkParsed.chunk !== undefined) {
1317
+ if (creditState)
1318
+ creditState.chunksReceived++
1319
+ readable.push(chunkParsed.chunk)
1320
+ }
1321
+ if (chunkParsed.final) {
1322
+ streamEnded = true
1323
+ clearPushTimeout()
1324
+ readable.push(null)
1325
+ }
1326
+ }
1327
+ })
1328
+ reqSpool.roll(() =&gt; { this.onResponse.delete(`sink-push-chunk:${requestId}`) })
1329
+ &nbsp;
1330
+ /* start timeout for push stream cleanup */
1331
+ refreshPushTimeout()
1332
+ reqSpool.roll(() =&gt; { clearPushTimeout() })
1333
+ &nbsp;
1334
+ /* prepare info object */
1335
+ const promise = streamToBuffer(readable)
1336
+ const streamDone = new Promise&lt;void&gt;((resolve, reject) =&gt; {
1337
+ readable.once("end", () =&gt; { resolve() })
1338
+ readable.once("error", (err) =&gt; { reject(err) })
1339
+ })
1340
+ streamDone.catch(() =&gt; {}) /* avoid unhandled promise rejection */
1341
+ const info: InfoSink = {
1342
+ sender,
1343
+ stream: readable,
1344
+ buffer: promise
1345
+ }
1346
+ if (receiver)
1347
+ <span class="branch-0 cbranch-no" title="branch not covered" > info.receiver = receiver</span>
1348
+ if (authenticated !== undefined)
1349
+ <span class="branch-0 cbranch-no" title="branch not covered" > info.authenticated = authenticated</span>
1350
+ if (request.meta)
1351
+ info.meta = request.meta
1352
+ makeMutuallyExclusiveFields(info, "stream", "buffer")
1353
+ &nbsp;
1354
+ /* send ack response */
1355
+ await sendResponse(undefined, true)
1356
+ &nbsp;
1357
+ /* call handler */
1358
+ await callback(...params, info)
1359
+ &nbsp;
1360
+ /* ensure stream is consumed or destroyed to prevent hang */
1361
+ if (readable.readableFlowing !== <span class="branch-0 cbranch-no" title="branch not covered" >true &amp;&amp; !readable.destroyed)</span>
1362
+ <span class="branch-0 cbranch-no" title="branch not covered" > readable.resume()</span>
1363
+ &nbsp;
1364
+ /* await full stream consumption before confirming success */
1365
+ await streamDone
1366
+ &nbsp;
1367
+ /* send terminal success response */
1368
+ try {
1369
+ await sendResponse()
1370
+ <span class="branch-0 cbranch-no" title="branch not covered" > }</span>
1371
+ <span class="cstat-no" title="statement not covered" > catch (err2: unknown) {</span>
1372
+ <span class="cstat-no" title="statement not covered" > this.error(ensureError(err2), `sending terminal response for sink "${name}" failed`)</span>
1373
+ <span class="cstat-no" title="statement not covered" > }</span>
1374
+ }
1375
+ catch (err: unknown) {
1376
+ const error = ensureError(err, `handler for sink "${name}" failed`)
1377
+ &nbsp;
1378
+ /* send error as nak response or as mid-stream error response */
1379
+ this.error(error)
1380
+ await sendResponse(error.message).catch(() =&gt; {})
1381
+ }
1382
+ finally {
1383
+ /* cleanup resources */
1384
+ const stream = this.pushStreams.get(requestId)
1385
+ if (stream !== undefined &amp;&amp; !stream.destroyed)
1386
+ <span class="branch-0 cbranch-no" title="branch not covered" > stream.destroy()</span>
1387
+ await reqSpool.unroll()
1388
+ }
1389
+ })
1390
+ spool.roll(() =&gt; { this.onRequest.delete(`sink-push-request:${name}`) })
1391
+ &nbsp;
1392
+ /* subscribe to MQTT topics */
1393
+ await this.subscribeTopicAndSpool(spool, topicReqB, options)
1394
+ await this.subscribeTopicAndSpool(spool, topicReqD, options)
1395
+ &nbsp;
1396
+ /* provide a registration for subsequent destruction */
1397
+ return this.makeRegistration(spool, "sink", name, `sink-push-request:${name}`)
1398
+ }
1399
+ &nbsp;
1400
+ /* push to sink ("chunked content") */
1401
+ async push&lt;K extends SinkKeys&lt;T&gt; &amp; string&gt; (
1402
+ name: K,
1403
+ data: Readable | Uint8Array,
1404
+ ...params: Parameters&lt;T[K]&gt;
1405
+ ): Promise&lt;void&gt;
1406
+ async push&lt;K extends SinkKeys&lt;T&gt; &amp; string&gt; (
1407
+ config: {
1408
+ name: K,
1409
+ data: Readable | Uint8Array,
1410
+ params: Parameters&lt;T[K]&gt;,
1411
+ receiver?: string,
1412
+ options?: IClientPublishOptions,
1413
+ meta?: Record&lt;string, any&gt;
1414
+ }
1415
+ ): Promise&lt;void&gt;
1416
+ async push&lt;K extends SinkKeys&lt;T&gt; &amp; string&gt; (
1417
+ nameOrConfig: K | {
1418
+ name: K,
1419
+ data: Readable | Uint8Array,
1420
+ params: Parameters&lt;T[K]&gt;,
1421
+ receiver?: string,
1422
+ options?: IClientPublishOptions,
1423
+ meta?: Record&lt;string, any&gt;
1424
+ },
1425
+ ...args: any[]
1426
+ ): Promise&lt;void&gt; {
1427
+ /* determine actual parameters */
1428
+ let name: K
1429
+ let data: Readable | Uint8Array
1430
+ let params: Parameters&lt;T[K]&gt;
1431
+ let receiver: string | undefined
1432
+ let options: IClientPublishOptions = {}
1433
+ let meta: Record&lt;string, any&gt; | undefined
1434
+ if (typeof nameOrConfig === "object" &amp;&amp; nameOrConfig !== null) {
1435
+ /* object-based API */
1436
+ name = nameOrConfig.name
1437
+ data = nameOrConfig.data
1438
+ params = nameOrConfig.params
1439
+ receiver = nameOrConfig.receiver
1440
+ options = nameOrConfig.options ?? {}
1441
+ meta = nameOrConfig.meta
1442
+ }
1443
+ else {
1444
+ /* positional API */
1445
+ name = nameOrConfig
1446
+ data = args[0]
1447
+ params = args.slice(1) as Parameters&lt;T[K]&gt;
1448
+ }
1449
+ &nbsp;
1450
+ /* sanity check data type */
1451
+ if (!(data instanceof Readable) &amp;&amp; !(data instanceof Uint8Array))
1452
+ <span class="branch-0 cbranch-no" title="branch not covered" > throw new Error("invalid data type: expected Readable or Uint8Array")</span>
1453
+ &nbsp;
1454
+ /* create a resource spool */
1455
+ const spool = new Spool()
1456
+ &nbsp;
1457
+ /* generate unique request id */
1458
+ let requestId = nanoid()
1459
+ while (this.onResponse.has(`sink-push-response:${requestId}`)
1460
+ || this.onResponse.has(`sink-push-credit:${requestId}`))
1461
+ <span class="branch-0 cbranch-no" title="branch not covered" > requestId = nanoid()</span>
1462
+ &nbsp;
1463
+ /* subscribe to response topic (for ack/nak) */
1464
+ const responseTopic = this.options.topicMake(name, "sink-push-response", this.options.id)
1465
+ await this.subscribeTopicAndSpool(spool, responseTopic, { qos: options.qos ?? 2 })
1466
+ &nbsp;
1467
+ /* define abort controller and signal */
1468
+ const abortController = new AbortController()
1469
+ const abortSignal = abortController.signal
1470
+ &nbsp;
1471
+ /* ensure stream gets destroyed on abort */
1472
+ if (data instanceof Readable) {
1473
+ const stream = data
1474
+ abortSignal.addEventListener("abort", () =&gt; {
1475
+ if (!stream.destroyed)
1476
+ <span class="branch-0 cbranch-no" title="branch not covered" > stream.destroy(ensureError(abortSignal.reason))</span>
1477
+ }, { once: true })
1478
+ }
1479
+ &nbsp;
1480
+ /* utility function for timeout refresh */
1481
+ const pushTimerId = `sink-push-send:${requestId}`
1482
+ const refreshTimeout = () =&gt; this.timerRefresh(pushTimerId, () =&gt; {
1483
+ <span class="cstat-no" title="statement not covered" > const error = new Error(`push to sink "${name}" timed out`)</span>
1484
+ <span class="cstat-no" title="statement not covered" > abortController.abort(error)</span>
1485
+ <span class="cstat-no" title="statement not covered" > spool.unroll()</span>
1486
+ })
1487
+ spool.roll(() =&gt; { this.timerClear(pushTimerId) })
1488
+ &nbsp;
1489
+ /* start timeout handler */
1490
+ refreshTimeout()
1491
+ &nbsp;
1492
+ /* send request and wait for response before sending chunks */
1493
+ let initialCredit: number | undefined
1494
+ let creditGate: CreditGate | undefined
1495
+ let remoteError = false
1496
+ let pushAcked = false
1497
+ let pushFinalized = false
1498
+ let pushDataFinalSent = false
1499
+ let pushFinalizeResolve!: () =&gt; void
1500
+ let pushFinalizeReject!: (reason?: any) =&gt; void
1501
+ const pushFinalize = new Promise&lt;void&gt;((resolve, reject) =&gt; {
1502
+ pushFinalizeResolve = resolve
1503
+ pushFinalizeReject = reject
1504
+ })
1505
+ pushFinalize.catch(() =&gt; {}) /* avoid unhandled promise rejection */
1506
+ try {
1507
+ await new Promise&lt;void&gt;((resolve, reject) =&gt; {
1508
+ /* handle abort signal */
1509
+ const onAbort = () =&gt; { reject(abortSignal.reason) }
1510
+ abortSignal.addEventListener("abort", onAbort, { once: true })
1511
+ spool.roll(() =&gt; { abortSignal.removeEventListener("abort", onAbort) })
1512
+ &nbsp;
1513
+ /* register handlers for initial response */
1514
+ this.onResponse.set(`sink-push-response:${requestId}`, (response: SinkPushResponse) =&gt; {
1515
+ if (response.error)
1516
+ <span class="branch-0 cbranch-no" title="branch not covered" > reject(new Error(response.error))</span>
1517
+ else {
1518
+ if (response.sender)
1519
+ receiver = response.sender
1520
+ initialCredit = response.credit
1521
+ pushAcked = true
1522
+ resolve()
1523
+ }
1524
+ })
1525
+ spool.roll(() =&gt; { this.onResponse.delete(`sink-push-response:${requestId}`) })
1526
+ &nbsp;
1527
+ /* generate and send request message */
1528
+ const auth = this.authenticate()
1529
+ const metaStore = this.metaStore(meta)
1530
+ const request = this.msg.makeSinkPushRequest(requestId,
1531
+ name, params, this.options.id, receiver, auth, metaStore)
1532
+ const message = this.codec.encode(request)
1533
+ const requestTopic = this.options.topicMake(name, "sink-push-request", receiver)
1534
+ run(`publish push request as MQTT message to topic "${requestTopic}"`, spool, () =&gt;
1535
+ this.publishToTopic(requestTopic, message, { qos: 2, ...options })).catch((err: Error) =&gt; {
1536
+ <span class="cstat-no" title="statement not covered" > reject(err)</span>
1537
+ })
1538
+ })
1539
+ &nbsp;
1540
+ /* override handler for mid-stream (error) responses */
1541
+ this.onResponse.set(`sink-push-response:${requestId}`, (response: SinkPushResponse) =&gt; {
1542
+ if (response.error) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
1543
+ <span class="cstat-no" title="statement not covered" > remoteError = true</span>
1544
+ <span class="cstat-no" title="statement not covered" > pushFinalizeReject(new Error(response.error))</span>
1545
+ <span class="cstat-no" title="statement not covered" > abortController.abort(new Error(response.error))</span>
1546
+ <span class="cstat-no" title="statement not covered" > }</span>
1547
+ else if (pushAcked &amp;&amp; !pushFinalized) {
1548
+ pushFinalized = true
1549
+ pushFinalizeResolve()
1550
+ }
1551
+ })
1552
+ &nbsp;
1553
+ /* create credit gate for flow control (if server granted credit) */
1554
+ if (initialCredit !== undefined &amp;&amp; initialCredit &gt; 0)
1555
+ creditGate = new CreditGate(initialCredit)
1556
+ &nbsp;
1557
+ /* register credit callback for flow control (credit arrives on response topic) */
1558
+ if (creditGate) {
1559
+ const gate = creditGate
1560
+ spool.roll(() =&gt; { gate.abort() })
1561
+ this.onResponse.set(`sink-push-credit:${requestId}`, (response: SinkPushCredit) =&gt; {
1562
+ gate.replenish(response.credit)
1563
+ refreshTimeout()
1564
+ })
1565
+ spool.roll(() =&gt; { this.onResponse.delete(`sink-push-credit:${requestId}`) })
1566
+ }
1567
+ &nbsp;
1568
+ /* generate corresponding MQTT topic for chunks (use request topic) */
1569
+ const chunkTopic = this.options.topicMake(name, "sink-push-request", receiver)
1570
+ &nbsp;
1571
+ /* callback for creating and sending a chunk message */
1572
+ const sendChunk = async (
1573
+ chunk: Uint8Array | undefined,
1574
+ error: string | undefined,
1575
+ final: boolean
1576
+ ): Promise&lt;void&gt; =&gt; {
1577
+ refreshTimeout()
1578
+ const chunkMsg = this.msg.makeSinkPushChunk(requestId,
1579
+ name, chunk, error, final, this.options.id, receiver)
1580
+ const message = this.codec.encode(chunkMsg)
1581
+ await this.publishToTopic(chunkTopic, message, { qos: 2, ...options })
1582
+ if (error === undefined &amp;&amp; final)
1583
+ pushDataFinalSent = true
1584
+ }
1585
+ &nbsp;
1586
+ /* iterate over all chunks of the buffer */
1587
+ if (data instanceof Readable)
1588
+ /* attach to the readable */
1589
+ await sendStreamAsChunks(data, this.options.chunkSize, sendChunk, creditGate, abortSignal)
1590
+ else if (data instanceof Uint8Array)
1591
+ /* split buffer into chunks and send them */
1592
+ await sendBufferAsChunks(data, this.options.chunkSize, sendChunk, creditGate, abortSignal)
1593
+ &nbsp;
1594
+ /* wait for terminal sink response */
1595
+ if (!pushFinalized) {
1596
+ await new Promise&lt;void&gt;((resolve, reject) =&gt; {
1597
+ const onAbort = () =&gt; { reject(abortSignal.reason) }
1598
+ abortSignal.addEventListener("abort", onAbort, { once: true })
1599
+ pushFinalize.then(resolve, reject).finally(() =&gt; {
1600
+ abortSignal.removeEventListener("abort", onAbort)
1601
+ })
1602
+ })
1603
+ }
1604
+ }
1605
+ catch (err: unknown) {
1606
+ const error = ensureError(err)
1607
+ abortController.abort(error)
1608
+ &nbsp;
1609
+ /* send error chunk only if push was acked and error did not originate from receiver
1610
+ (before ack, the sink has no chunk handler yet and will time out on its own;
1611
+ after final data chunk, no additional terminal chunk should be sent) */
1612
+ if (pushAcked &amp;&amp; !remoteError &amp;&amp; !pushDataFinalSent) {
1613
+ const chunkTopic = this.options.topicMake(name, "sink-push-request", receiver)
1614
+ const chunkMsg = this.msg.makeSinkPushChunk(requestId,
1615
+ name, undefined, error.message, true, this.options.id, receiver)
1616
+ const message = this.codec.encode(chunkMsg)
1617
+ await this.publishToTopic(chunkTopic, message, { qos: 2, ...options }).catch(() =&gt; {})
1618
+ }
1619
+ throw err
1620
+ }
1621
+ finally {
1622
+ await spool.unroll()
1623
+ }
1624
+ }
1625
+ <span class="cstat-no" title="statement not covered" ><span class="branch-0 cbranch-no" title="branch not covered" >}</span></span>
1626
+ &nbsp;</pre></td></tr></table></pre>
1627
+
1628
+ <div class='push'></div><!-- for sticky footer -->
1629
+ </div><!-- /wrapper -->
1630
+ <div class='footer quiet pad2 space-top1 center small'>
1631
+ Code coverage generated by
1632
+ <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
1633
+ at 2026-03-14T22:41:38.599Z
1634
+ </div>
1635
+ <script src="prettify.js"></script>
1636
+ <script>
1637
+ window.onload = function () {
1638
+ prettyPrint();
1639
+ };
1640
+ </script>
1641
+ <script src="sorter.js"></script>
1642
+ <script src="block-navigation.js"></script>
1643
+ </body>
1644
+ </html>
1645
+