a2acalling 0.6.74 → 0.6.75

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 (118) hide show
  1. package/.a2a-manifest.json +2 -2
  2. package/.c8rc.json +16 -0
  3. package/.node-version +1 -0
  4. package/.serena/project.yml +126 -0
  5. package/ARCHITECTURE.md +11 -0
  6. package/CONVENTIONS.md +9 -0
  7. package/coverage/base.css +224 -0
  8. package/coverage/block-navigation.js +87 -0
  9. package/coverage/favicon.png +0 -0
  10. package/coverage/index.html +146 -0
  11. package/coverage/prettify.css +1 -0
  12. package/coverage/prettify.js +2 -0
  13. package/coverage/sort-arrow-sprite.png +0 -0
  14. package/coverage/sorter.js +210 -0
  15. package/coverage/src/index.html +131 -0
  16. package/coverage/src/index.js.html +313 -0
  17. package/coverage/src/lib/agent-card.js.html +418 -0
  18. package/coverage/src/lib/call-monitor.js.html +700 -0
  19. package/coverage/src/lib/callbook.js.html +1183 -0
  20. package/coverage/src/lib/claude-subagent.js.html +2173 -0
  21. package/coverage/src/lib/client.js.html +2134 -0
  22. package/coverage/src/lib/config.js.html +1525 -0
  23. package/coverage/src/lib/conversation-driver.js.html +1909 -0
  24. package/coverage/src/lib/conversations.js.html +2575 -0
  25. package/coverage/src/lib/crypto.js.html +424 -0
  26. package/coverage/src/lib/dashboard-events.js.html +724 -0
  27. package/coverage/src/lib/disclosure.js.html +2461 -0
  28. package/coverage/src/lib/external-ip.js.html +718 -0
  29. package/coverage/src/lib/index.html +506 -0
  30. package/coverage/src/lib/invite-host.js.html +754 -0
  31. package/coverage/src/lib/local-request.js.html +292 -0
  32. package/coverage/src/lib/logger.js.html +2116 -0
  33. package/coverage/src/lib/openclaw-integration.js.html +1102 -0
  34. package/coverage/src/lib/pid-file.js.html +394 -0
  35. package/coverage/src/lib/port-scanner.js.html +334 -0
  36. package/coverage/src/lib/prompt-template.js.html +1150 -0
  37. package/coverage/src/lib/runtime-adapter.js.html +2188 -0
  38. package/coverage/src/lib/summarizer.js.html +553 -0
  39. package/coverage/src/lib/summary-formatter.js.html +589 -0
  40. package/coverage/src/lib/summary-prompt.js.html +694 -0
  41. package/coverage/src/lib/tokens.js.html +2689 -0
  42. package/coverage/src/lib/turn-timeout.js.html +241 -0
  43. package/coverage/src/lib/update-checker.js.html +364 -0
  44. package/coverage/src/lib/update-manager.js.html +1024 -0
  45. package/coverage/src/routes/a2a.js.html +3724 -0
  46. package/coverage/src/routes/callbook.js.html +511 -0
  47. package/coverage/src/routes/dashboard.js.html +4819 -0
  48. package/coverage/src/routes/index.html +146 -0
  49. package/coverage/src/server.js.html +3622 -0
  50. package/coverage/tmp/coverage-1605378-1772576706365-0.json +1 -0
  51. package/coverage/tmp/coverage-1605384-1772576607459-0.json +1 -0
  52. package/coverage/tmp/coverage-1605410-1772576631155-0.json +1 -0
  53. package/coverage/tmp/coverage-1606942-1772576636869-0.json +1 -0
  54. package/coverage/tmp/coverage-1607004-1772576637454-0.json +1 -0
  55. package/coverage/tmp/coverage-1607044-1772576637876-0.json +1 -0
  56. package/coverage/tmp/coverage-1607096-1772576638356-0.json +1 -0
  57. package/coverage/tmp/coverage-1607145-1772576638777-0.json +1 -0
  58. package/coverage/tmp/coverage-1607201-1772576639277-0.json +1 -0
  59. package/coverage/tmp/coverage-1607247-1772576639755-0.json +1 -0
  60. package/coverage/tmp/coverage-1607317-1772576640083-0.json +1 -0
  61. package/coverage/tmp/coverage-1607381-1772576640465-0.json +1 -0
  62. package/coverage/tmp/coverage-1607446-1772576640868-0.json +1 -0
  63. package/coverage/tmp/coverage-1607501-1772576641662-0.json +1 -0
  64. package/coverage/tmp/coverage-1607534-1772576641565-0.json +1 -0
  65. package/coverage/tmp/coverage-1607627-1772576641871-0.json +1 -0
  66. package/coverage/tmp/coverage-1607665-1772576642172-0.json +1 -0
  67. package/coverage/tmp/coverage-1607714-1772576642577-0.json +1 -0
  68. package/coverage/tmp/coverage-1607788-1772576643466-0.json +1 -0
  69. package/coverage/tmp/coverage-1607924-1772576644678-0.json +1 -0
  70. package/coverage/tmp/coverage-1607978-1772576645154-0.json +1 -0
  71. package/coverage/tmp/coverage-1608035-1772576645564-0.json +1 -0
  72. package/coverage/tmp/coverage-1608106-1772576645967-0.json +1 -0
  73. package/coverage/tmp/coverage-1608179-1772576648656-0.json +1 -0
  74. package/coverage/tmp/coverage-1608196-1772576647367-0.json +1 -0
  75. package/coverage/tmp/coverage-1608217-1772576648557-0.json +1 -0
  76. package/coverage/tmp/coverage-1608256-1772576651378-0.json +1 -0
  77. package/coverage/tmp/coverage-1608265-1772576650058-0.json +1 -0
  78. package/coverage/tmp/coverage-1608289-1772576651358-0.json +1 -0
  79. package/coverage/tmp/coverage-1608591-1772576660465-0.json +1 -0
  80. package/coverage/tmp/coverage-1608648-1772576659272-0.json +1 -0
  81. package/coverage/tmp/coverage-1608665-1772576660374-0.json +1 -0
  82. package/coverage/tmp/coverage-1608677-1772576661268-0.json +1 -0
  83. package/coverage/tmp/coverage-1608684-1772576663968-0.json +1 -0
  84. package/coverage/tmp/coverage-1608692-1772576662575-0.json +1 -0
  85. package/coverage/tmp/coverage-1608701-1772576663873-0.json +1 -0
  86. package/coverage/tmp/coverage-1608718-1772576666674-0.json +1 -0
  87. package/coverage/tmp/coverage-1608725-1772576665463-0.json +1 -0
  88. package/coverage/tmp/coverage-1608738-1772576666577-0.json +1 -0
  89. package/coverage/tmp/coverage-1608753-1772576669664-0.json +1 -0
  90. package/coverage/tmp/coverage-1608763-1772576668275-0.json +1 -0
  91. package/coverage/tmp/coverage-1608771-1772576669563-0.json +1 -0
  92. package/coverage/tmp/coverage-1608828-1772576676574-0.json +1 -0
  93. package/coverage/tmp/coverage-1609244-1772576675272-0.json +1 -0
  94. package/coverage/tmp/coverage-1609342-1772576676478-0.json +1 -0
  95. package/coverage/tmp/coverage-1609450-1772576686954-0.json +1 -0
  96. package/coverage/tmp/coverage-1609841-1772576685466-0.json +1 -0
  97. package/coverage/tmp/coverage-1609925-1772576686855-0.json +1 -0
  98. package/coverage/tmp/coverage-1610399-1772576692469-0.json +1 -0
  99. package/coverage/tmp/coverage-1611283-1772576703062-0.json +1 -0
  100. package/coverage/tmp/coverage-1611294-1772576703755-0.json +1 -0
  101. package/docs/plans/2026-03-03-a2a-91-macos-packaging-plan.md +144 -0
  102. package/docs/signing-setup.md +49 -0
  103. package/native/macos/certs/appldevcert.cer +0 -0
  104. package/native/macos/src-tauri/binaries/.gitkeep +0 -0
  105. package/native/macos/src-tauri/capabilities/default.json +11 -1
  106. package/native/macos/src-tauri/entitlements.plist +14 -0
  107. package/native/macos/src-tauri/src/discovery.rs +14 -3
  108. package/native/macos/src-tauri/src/health.rs +4 -0
  109. package/native/macos/src-tauri/src/lib.rs +52 -11
  110. package/native/macos/src-tauri/src/server.rs +262 -26
  111. package/native/macos/src-tauri/tauri.conf.json +13 -4
  112. package/package.json +7 -2
  113. package/pkg.config.json +14 -0
  114. package/scripts/build-standalone.sh +106 -0
  115. package/scripts/smoke-test-standalone.sh +101 -0
  116. package/scripts/sync-version.sh +28 -0
  117. package/scripts/verify-app-bundle.sh +34 -0
  118. package/.maestro/inbox/release-workflow-spam.md +0 -25
@@ -0,0 +1,1183 @@
1
+
2
+ <!doctype html>
3
+ <html lang="en">
4
+
5
+ <head>
6
+ <title>Code coverage report for src/lib/callbook.js</title>
7
+ <meta charset="utf-8" />
8
+ <link rel="stylesheet" href="../../prettify.css" />
9
+ <link rel="stylesheet" href="../../base.css" />
10
+ <link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
11
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
12
+ <style type='text/css'>
13
+ .coverage-summary .sorter {
14
+ background-image: url(../../sort-arrow-sprite.png);
15
+ }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <div class='wrapper'>
21
+ <div class='pad1'>
22
+ <h1><a href="../../index.html">All files</a> / <a href="index.html">src/lib</a> callbook.js</h1>
23
+ <div class='clearfix'>
24
+
25
+ <div class='fl pad1y space-right2'>
26
+ <span class="strong">95.34% </span>
27
+ <span class="quiet">Statements</span>
28
+ <span class='fraction'>348/365</span>
29
+ </div>
30
+
31
+
32
+ <div class='fl pad1y space-right2'>
33
+ <span class="strong">78.04% </span>
34
+ <span class="quiet">Branches</span>
35
+ <span class='fraction'>64/82</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'>16/16</span>
43
+ </div>
44
+
45
+
46
+ <div class='fl pad1y space-right2'>
47
+ <span class="strong">95.34% </span>
48
+ <span class="quiet">Lines</span>
49
+ <span class='fraction'>348/365</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></td><td class="line-coverage quiet"><span class="cline-any cline-yes">29x</span>
433
+ <span class="cline-any cline-yes">29x</span>
434
+ <span class="cline-any cline-yes">29x</span>
435
+ <span class="cline-any cline-yes">29x</span>
436
+ <span class="cline-any cline-yes">29x</span>
437
+ <span class="cline-any cline-yes">29x</span>
438
+ <span class="cline-any cline-yes">29x</span>
439
+ <span class="cline-any cline-yes">29x</span>
440
+ <span class="cline-any cline-yes">29x</span>
441
+ <span class="cline-any cline-yes">29x</span>
442
+ <span class="cline-any cline-yes">29x</span>
443
+ <span class="cline-any cline-yes">29x</span>
444
+ <span class="cline-any cline-yes">29x</span>
445
+ <span class="cline-any cline-yes">29x</span>
446
+ <span class="cline-any cline-yes">29x</span>
447
+ <span class="cline-any cline-yes">29x</span>
448
+ <span class="cline-any cline-yes">29x</span>
449
+ <span class="cline-any cline-yes">29x</span>
450
+ <span class="cline-any cline-yes">29x</span>
451
+ <span class="cline-any cline-yes">29x</span>
452
+ <span class="cline-any cline-yes">29x</span>
453
+ <span class="cline-any cline-yes">29x</span>
454
+ <span class="cline-any cline-yes">29x</span>
455
+ <span class="cline-any cline-yes">29x</span>
456
+ <span class="cline-any cline-yes">29x</span>
457
+ <span class="cline-any cline-yes">46x</span>
458
+ <span class="cline-any cline-yes">46x</span>
459
+ <span class="cline-any cline-yes">46x</span>
460
+ <span class="cline-any cline-yes">29x</span>
461
+ <span class="cline-any cline-yes">65x</span>
462
+ <span class="cline-any cline-yes">65x</span>
463
+ <span class="cline-any cline-yes">65x</span>
464
+ <span class="cline-any cline-yes">29x</span>
465
+ <span class="cline-any cline-yes">36x</span>
466
+ <span class="cline-any cline-yes">36x</span>
467
+ <span class="cline-any cline-yes">36x</span>
468
+ <span class="cline-any cline-yes">36x</span>
469
+ <span class="cline-any cline-yes">29x</span>
470
+ <span class="cline-any cline-yes">29x</span>
471
+ <span class="cline-any cline-yes">29x</span>
472
+ <span class="cline-any cline-yes">58x</span>
473
+ <span class="cline-any cline-yes">58x</span>
474
+ <span class="cline-any cline-yes">58x</span>
475
+ <span class="cline-any cline-yes">58x</span>
476
+ <span class="cline-any cline-yes">58x</span>
477
+ <span class="cline-any cline-yes">58x</span>
478
+ <span class="cline-any cline-yes">58x</span>
479
+ <span class="cline-any cline-yes">29x</span>
480
+ <span class="cline-any cline-yes">29x</span>
481
+ <span class="cline-any cline-yes">58x</span>
482
+ <span class="cline-any cline-no">&nbsp;</span>
483
+ <span class="cline-any cline-no">&nbsp;</span>
484
+ <span class="cline-any cline-yes">58x</span>
485
+ <span class="cline-any cline-yes">29x</span>
486
+ <span class="cline-any cline-yes">29x</span>
487
+ <span class="cline-any cline-yes">83x</span>
488
+ <span class="cline-any cline-yes">83x</span>
489
+ <span class="cline-any cline-yes">24x</span>
490
+ <span class="cline-any cline-yes">24x</span>
491
+ <span class="cline-any cline-yes">24x</span>
492
+ <span class="cline-any cline-yes">24x</span>
493
+ <span class="cline-any cline-yes">24x</span>
494
+ <span class="cline-any cline-yes">83x</span>
495
+ <span class="cline-any cline-no">&nbsp;</span>
496
+ <span class="cline-any cline-no">&nbsp;</span>
497
+ <span class="cline-any cline-yes">24x</span>
498
+ <span class="cline-any cline-yes">24x</span>
499
+ <span class="cline-any cline-yes">24x</span>
500
+ <span class="cline-any cline-yes">83x</span>
501
+ <span class="cline-any cline-yes">2x</span>
502
+ <span class="cline-any cline-yes">2x</span>
503
+ <span class="cline-any cline-yes">2x</span>
504
+ <span class="cline-any cline-yes">83x</span>
505
+ <span class="cline-any cline-yes">29x</span>
506
+ <span class="cline-any cline-yes">29x</span>
507
+ <span class="cline-any cline-yes">24x</span>
508
+ <span class="cline-any cline-yes">24x</span>
509
+ <span class="cline-any cline-yes">24x</span>
510
+ <span class="cline-any cline-yes">24x</span>
511
+ <span class="cline-any cline-yes">24x</span>
512
+ <span class="cline-any cline-yes">24x</span>
513
+ <span class="cline-any cline-yes">24x</span>
514
+ <span class="cline-any cline-yes">24x</span>
515
+ <span class="cline-any cline-yes">24x</span>
516
+ <span class="cline-any cline-yes">24x</span>
517
+ <span class="cline-any cline-yes">24x</span>
518
+ <span class="cline-any cline-yes">24x</span>
519
+ <span class="cline-any cline-yes">24x</span>
520
+ <span class="cline-any cline-yes">24x</span>
521
+ <span class="cline-any cline-yes">24x</span>
522
+ <span class="cline-any cline-yes">24x</span>
523
+ <span class="cline-any cline-yes">24x</span>
524
+ <span class="cline-any cline-yes">24x</span>
525
+ <span class="cline-any cline-yes">24x</span>
526
+ <span class="cline-any cline-yes">24x</span>
527
+ <span class="cline-any cline-yes">24x</span>
528
+ <span class="cline-any cline-yes">24x</span>
529
+ <span class="cline-any cline-yes">24x</span>
530
+ <span class="cline-any cline-yes">24x</span>
531
+ <span class="cline-any cline-yes">24x</span>
532
+ <span class="cline-any cline-yes">24x</span>
533
+ <span class="cline-any cline-yes">24x</span>
534
+ <span class="cline-any cline-yes">24x</span>
535
+ <span class="cline-any cline-yes">24x</span>
536
+ <span class="cline-any cline-yes">24x</span>
537
+ <span class="cline-any cline-yes">24x</span>
538
+ <span class="cline-any cline-yes">24x</span>
539
+ <span class="cline-any cline-yes">24x</span>
540
+ <span class="cline-any cline-yes">24x</span>
541
+ <span class="cline-any cline-yes">24x</span>
542
+ <span class="cline-any cline-yes">24x</span>
543
+ <span class="cline-any cline-yes">24x</span>
544
+ <span class="cline-any cline-yes">24x</span>
545
+ <span class="cline-any cline-yes">24x</span>
546
+ <span class="cline-any cline-yes">29x</span>
547
+ <span class="cline-any cline-yes">29x</span>
548
+ <span class="cline-any cline-yes">22x</span>
549
+ <span class="cline-any cline-yes">22x</span>
550
+ <span class="cline-any cline-yes">22x</span>
551
+ <span class="cline-any cline-yes">22x</span>
552
+ <span class="cline-any cline-yes">22x</span>
553
+ <span class="cline-any cline-yes">22x</span>
554
+ <span class="cline-any cline-yes">22x</span>
555
+ <span class="cline-any cline-yes">22x</span>
556
+ <span class="cline-any cline-yes">22x</span>
557
+ <span class="cline-any cline-yes">22x</span>
558
+ <span class="cline-any cline-yes">22x</span>
559
+ <span class="cline-any cline-yes">22x</span>
560
+ <span class="cline-any cline-yes">22x</span>
561
+ <span class="cline-any cline-yes">22x</span>
562
+ <span class="cline-any cline-yes">22x</span>
563
+ <span class="cline-any cline-yes">22x</span>
564
+ <span class="cline-any cline-yes">22x</span>
565
+ <span class="cline-any cline-yes">22x</span>
566
+ <span class="cline-any cline-yes">22x</span>
567
+ <span class="cline-any cline-yes">22x</span>
568
+ <span class="cline-any cline-yes">22x</span>
569
+ <span class="cline-any cline-yes">22x</span>
570
+ <span class="cline-any cline-yes">22x</span>
571
+ <span class="cline-any cline-yes">22x</span>
572
+ <span class="cline-any cline-yes">22x</span>
573
+ <span class="cline-any cline-yes">22x</span>
574
+ <span class="cline-any cline-yes">22x</span>
575
+ <span class="cline-any cline-yes">22x</span>
576
+ <span class="cline-any cline-yes">22x</span>
577
+ <span class="cline-any cline-yes">22x</span>
578
+ <span class="cline-any cline-yes">22x</span>
579
+ <span class="cline-any cline-yes">22x</span>
580
+ <span class="cline-any cline-yes">22x</span>
581
+ <span class="cline-any cline-yes">22x</span>
582
+ <span class="cline-any cline-yes">22x</span>
583
+ <span class="cline-any cline-yes">22x</span>
584
+ <span class="cline-any cline-yes">22x</span>
585
+ <span class="cline-any cline-yes">22x</span>
586
+ <span class="cline-any cline-yes">22x</span>
587
+ <span class="cline-any cline-yes">22x</span>
588
+ <span class="cline-any cline-yes">22x</span>
589
+ <span class="cline-any cline-yes">22x</span>
590
+ <span class="cline-any cline-yes">22x</span>
591
+ <span class="cline-any cline-yes">22x</span>
592
+ <span class="cline-any cline-yes">22x</span>
593
+ <span class="cline-any cline-yes">22x</span>
594
+ <span class="cline-any cline-yes">22x</span>
595
+ <span class="cline-any cline-yes">22x</span>
596
+ <span class="cline-any cline-yes">22x</span>
597
+ <span class="cline-any cline-yes">22x</span>
598
+ <span class="cline-any cline-yes">22x</span>
599
+ <span class="cline-any cline-yes">22x</span>
600
+ <span class="cline-any cline-yes">22x</span>
601
+ <span class="cline-any cline-yes">29x</span>
602
+ <span class="cline-any cline-yes">29x</span>
603
+ <span class="cline-any cline-yes">18x</span>
604
+ <span class="cline-any cline-yes">18x</span>
605
+ <span class="cline-any cline-yes">29x</span>
606
+ <span class="cline-any cline-yes">29x</span>
607
+ <span class="cline-any cline-yes">2x</span>
608
+ <span class="cline-any cline-yes">2x</span>
609
+ <span class="cline-any cline-yes">2x</span>
610
+ <span class="cline-any cline-yes">29x</span>
611
+ <span class="cline-any cline-yes">29x</span>
612
+ <span class="cline-any cline-yes">29x</span>
613
+ <span class="cline-any cline-yes">29x</span>
614
+ <span class="cline-any cline-yes">29x</span>
615
+ <span class="cline-any cline-yes">29x</span>
616
+ <span class="cline-any cline-yes">21x</span>
617
+ <span class="cline-any cline-yes">21x</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">20x</span>
621
+ <span class="cline-any cline-yes">21x</span>
622
+ <span class="cline-any cline-yes">21x</span>
623
+ <span class="cline-any cline-yes">21x</span>
624
+ <span class="cline-any cline-yes">21x</span>
625
+ <span class="cline-any cline-yes">21x</span>
626
+ <span class="cline-any cline-yes">21x</span>
627
+ <span class="cline-any cline-yes">21x</span>
628
+ <span class="cline-any cline-yes">21x</span>
629
+ <span class="cline-any cline-yes">21x</span>
630
+ <span class="cline-any cline-yes">21x</span>
631
+ <span class="cline-any cline-yes">21x</span>
632
+ <span class="cline-any cline-yes">21x</span>
633
+ <span class="cline-any cline-yes">21x</span>
634
+ <span class="cline-any cline-yes">21x</span>
635
+ <span class="cline-any cline-yes">21x</span>
636
+ <span class="cline-any cline-yes">21x</span>
637
+ <span class="cline-any cline-yes">21x</span>
638
+ <span class="cline-any cline-yes">21x</span>
639
+ <span class="cline-any cline-yes">21x</span>
640
+ <span class="cline-any cline-yes">21x</span>
641
+ <span class="cline-any cline-yes">21x</span>
642
+ <span class="cline-any cline-yes">21x</span>
643
+ <span class="cline-any cline-yes">21x</span>
644
+ <span class="cline-any cline-yes">21x</span>
645
+ <span class="cline-any cline-yes">21x</span>
646
+ <span class="cline-any cline-yes">21x</span>
647
+ <span class="cline-any cline-yes">21x</span>
648
+ <span class="cline-any cline-yes">21x</span>
649
+ <span class="cline-any cline-yes">29x</span>
650
+ <span class="cline-any cline-yes">29x</span>
651
+ <span class="cline-any cline-yes">29x</span>
652
+ <span class="cline-any cline-yes">29x</span>
653
+ <span class="cline-any cline-yes">29x</span>
654
+ <span class="cline-any cline-yes">29x</span>
655
+ <span class="cline-any cline-yes">21x</span>
656
+ <span class="cline-any cline-yes">21x</span>
657
+ <span class="cline-any cline-no">&nbsp;</span>
658
+ <span class="cline-any cline-no">&nbsp;</span>
659
+ <span class="cline-any cline-yes">21x</span>
660
+ <span class="cline-any cline-yes">21x</span>
661
+ <span class="cline-any cline-yes">21x</span>
662
+ <span class="cline-any cline-yes">1x</span>
663
+ <span class="cline-any cline-yes">1x</span>
664
+ <span class="cline-any cline-yes">20x</span>
665
+ <span class="cline-any cline-yes">20x</span>
666
+ <span class="cline-any cline-yes">20x</span>
667
+ <span class="cline-any cline-yes">21x</span>
668
+ <span class="cline-any cline-yes">1x</span>
669
+ <span class="cline-any cline-yes">1x</span>
670
+ <span class="cline-any cline-yes">19x</span>
671
+ <span class="cline-any cline-yes">19x</span>
672
+ <span class="cline-any cline-yes">19x</span>
673
+ <span class="cline-any cline-yes">21x</span>
674
+ <span class="cline-any cline-yes">1x</span>
675
+ <span class="cline-any cline-yes">1x</span>
676
+ <span class="cline-any cline-yes">21x</span>
677
+ <span class="cline-any cline-yes">2x</span>
678
+ <span class="cline-any cline-yes">2x</span>
679
+ <span class="cline-any cline-yes">16x</span>
680
+ <span class="cline-any cline-yes">16x</span>
681
+ <span class="cline-any cline-yes">16x</span>
682
+ <span class="cline-any cline-yes">16x</span>
683
+ <span class="cline-any cline-yes">16x</span>
684
+ <span class="cline-any cline-no">&nbsp;</span>
685
+ <span class="cline-any cline-no">&nbsp;</span>
686
+ <span class="cline-any cline-no">&nbsp;</span>
687
+ <span class="cline-any cline-yes">16x</span>
688
+ <span class="cline-any cline-yes">16x</span>
689
+ <span class="cline-any cline-yes">16x</span>
690
+ <span class="cline-any cline-yes">16x</span>
691
+ <span class="cline-any cline-yes">16x</span>
692
+ <span class="cline-any cline-yes">16x</span>
693
+ <span class="cline-any cline-yes">16x</span>
694
+ <span class="cline-any cline-yes">16x</span>
695
+ <span class="cline-any cline-yes">16x</span>
696
+ <span class="cline-any cline-yes">16x</span>
697
+ <span class="cline-any cline-yes">16x</span>
698
+ <span class="cline-any cline-yes">16x</span>
699
+ <span class="cline-any cline-yes">16x</span>
700
+ <span class="cline-any cline-yes">16x</span>
701
+ <span class="cline-any cline-yes">16x</span>
702
+ <span class="cline-any cline-yes">16x</span>
703
+ <span class="cline-any cline-yes">16x</span>
704
+ <span class="cline-any cline-yes">16x</span>
705
+ <span class="cline-any cline-yes">16x</span>
706
+ <span class="cline-any cline-yes">16x</span>
707
+ <span class="cline-any cline-yes">16x</span>
708
+ <span class="cline-any cline-yes">16x</span>
709
+ <span class="cline-any cline-yes">16x</span>
710
+ <span class="cline-any cline-yes">16x</span>
711
+ <span class="cline-any cline-yes">16x</span>
712
+ <span class="cline-any cline-yes">16x</span>
713
+ <span class="cline-any cline-yes">16x</span>
714
+ <span class="cline-any cline-yes">16x</span>
715
+ <span class="cline-any cline-yes">16x</span>
716
+ <span class="cline-any cline-yes">16x</span>
717
+ <span class="cline-any cline-yes">16x</span>
718
+ <span class="cline-any cline-yes">16x</span>
719
+ <span class="cline-any cline-yes">21x</span>
720
+ <span class="cline-any cline-yes">29x</span>
721
+ <span class="cline-any cline-yes">29x</span>
722
+ <span class="cline-any cline-yes">29x</span>
723
+ <span class="cline-any cline-yes">29x</span>
724
+ <span class="cline-any cline-yes">29x</span>
725
+ <span class="cline-any cline-yes">29x</span>
726
+ <span class="cline-any cline-yes">10x</span>
727
+ <span class="cline-any cline-yes">10x</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-yes">10x</span>
731
+ <span class="cline-any cline-yes">10x</span>
732
+ <span class="cline-any cline-yes">10x</span>
733
+ <span class="cline-any cline-yes">9x</span>
734
+ <span class="cline-any cline-yes">9x</span>
735
+ <span class="cline-any cline-yes">10x</span>
736
+ <span class="cline-any cline-yes">10x</span>
737
+ <span class="cline-any cline-yes">5x</span>
738
+ <span class="cline-any cline-yes">5x</span>
739
+ <span class="cline-any cline-yes">10x</span>
740
+ <span class="cline-any cline-yes">10x</span>
741
+ <span class="cline-any cline-yes">5x</span>
742
+ <span class="cline-any cline-yes">5x</span>
743
+ <span class="cline-any cline-yes">5x</span>
744
+ <span class="cline-any cline-yes">5x</span>
745
+ <span class="cline-any cline-yes">5x</span>
746
+ <span class="cline-any cline-yes">10x</span>
747
+ <span class="cline-any cline-no">&nbsp;</span>
748
+ <span class="cline-any cline-no">&nbsp;</span>
749
+ <span class="cline-any cline-yes">5x</span>
750
+ <span class="cline-any cline-yes">5x</span>
751
+ <span class="cline-any cline-yes">10x</span>
752
+ <span class="cline-any cline-yes">29x</span>
753
+ <span class="cline-any cline-yes">29x</span>
754
+ <span class="cline-any cline-yes">5x</span>
755
+ <span class="cline-any cline-yes">5x</span>
756
+ <span class="cline-any cline-no">&nbsp;</span>
757
+ <span class="cline-any cline-no">&nbsp;</span>
758
+ <span class="cline-any cline-yes">5x</span>
759
+ <span class="cline-any cline-yes">5x</span>
760
+ <span class="cline-any cline-yes">5x</span>
761
+ <span class="cline-any cline-yes">5x</span>
762
+ <span class="cline-any cline-yes">5x</span>
763
+ <span class="cline-any cline-yes">5x</span>
764
+ <span class="cline-any cline-yes">29x</span>
765
+ <span class="cline-any cline-yes">29x</span>
766
+ <span class="cline-any cline-yes">6x</span>
767
+ <span class="cline-any cline-yes">6x</span>
768
+ <span class="cline-any cline-no">&nbsp;</span>
769
+ <span class="cline-any cline-no">&nbsp;</span>
770
+ <span class="cline-any cline-yes">6x</span>
771
+ <span class="cline-any cline-yes">6x</span>
772
+ <span class="cline-any cline-yes">5x</span>
773
+ <span class="cline-any cline-yes">5x</span>
774
+ <span class="cline-any cline-yes">5x</span>
775
+ <span class="cline-any cline-yes">5x</span>
776
+ <span class="cline-any cline-yes">4x</span>
777
+ <span class="cline-any cline-yes">4x</span>
778
+ <span class="cline-any cline-yes">4x</span>
779
+ <span class="cline-any cline-yes">5x</span>
780
+ <span class="cline-any cline-yes">5x</span>
781
+ <span class="cline-any cline-yes">6x</span>
782
+ <span class="cline-any cline-yes">29x</span>
783
+ <span class="cline-any cline-yes">29x</span>
784
+ <span class="cline-any cline-yes">29x</span>
785
+ <span class="cline-any cline-yes">24x</span>
786
+ <span class="cline-any cline-yes">21x</span>
787
+ <span class="cline-any cline-yes">21x</span>
788
+ <span class="cline-any cline-yes">21x</span>
789
+ <span class="cline-any cline-yes">24x</span>
790
+ <span class="cline-any cline-yes">29x</span>
791
+ <span class="cline-any cline-yes">29x</span>
792
+ <span class="cline-any cline-yes">29x</span>
793
+ <span class="cline-any cline-yes">29x</span>
794
+ <span class="cline-any cline-yes">29x</span>
795
+ <span class="cline-any cline-yes">29x</span>
796
+ <span class="cline-any cline-yes">29x</span>
797
+ <span class="cline-any cline-neutral">&nbsp;</span>
798
+ <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">/**
799
+ * Callbook Remote Auth
800
+ *
801
+ * Purpose:
802
+ * - Allow a remote owner UI ("Callbook Remote") to manage the dashboard safely.
803
+ * - Provisioning codes are short-lived and one-time use (safe-ish to share as an install link).
804
+ * - Sessions are long-lived (no expiration by default) and revocable.
805
+ *
806
+ * Storage:
807
+ * - SQLite DB at ~/.config/openclaw/a2a-callbook.db (or $A2A_CONFIG_DIR).
808
+ *
809
+ * Notes:
810
+ * - Secrets are never stored plaintext: only SHA-256 hashes are persisted.
811
+ */
812
+ &nbsp;
813
+ const fs = require('fs');
814
+ const path = require('path');
815
+ const crypto = require('crypto');
816
+ &nbsp;
817
+ const DEFAULT_CONFIG_DIR = process.env.A2A_CONFIG_DIR <span class="branch-0 cbranch-no" title="branch not covered" >||</span>
818
+ process.env.OPENCLAW_CONFIG_DIR <span class="branch-0 cbranch-no" title="branch not covered" >||</span>
819
+ path.join(process.env.HOME || '/tmp', '.config', 'openclaw');
820
+ &nbsp;
821
+ const DB_FILENAME = 'a2a-callbook.db';
822
+ &nbsp;
823
+ function nowIso() {
824
+ return new Date().toISOString();
825
+ }
826
+ &nbsp;
827
+ function sha256Hex(value) {
828
+ return crypto.createHash('sha256').update(String(value <span class="branch-0 cbranch-no" title="branch not covered" >|| '')</span>).digest('hex');
829
+ }
830
+ &nbsp;
831
+ function randomToken(prefix = '') {
832
+ const token = crypto.randomBytes(32).toString('base64url');
833
+ return prefix ? `${prefix}${token}` <span class="branch-0 cbranch-no" title="branch not covered" >: token;</span>
834
+ }
835
+ &nbsp;
836
+ class CallbookStore {
837
+ constructor(configDir = DEFAULT_CONFIG_DIR, options = {}) {
838
+ this.configDir = configDir;
839
+ this.dbPath = options.dbPath || path.join(configDir, DB_FILENAME);
840
+ this.db = null;
841
+ this._dbError = null;
842
+ this._stmts = null;
843
+ this._ensureDir();
844
+ }
845
+ &nbsp;
846
+ _ensureDir() {
847
+ if (!fs.existsSync(this.configDir)) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
848
+ <span class="cstat-no" title="statement not covered" > fs.mkdirSync(this.configDir, { recursive: true });</span>
849
+ <span class="cstat-no" title="statement not covered" > }</span>
850
+ }
851
+ &nbsp;
852
+ _initDb() {
853
+ if (this.db) return this.db;
854
+ if (this._dbError) <span class="branch-0 cbranch-no" title="branch not covered" >return null;</span>
855
+ try {
856
+ const Database = require('better-sqlite3');
857
+ this.db = new Database(this.dbPath);
858
+ try {
859
+ fs.chmodSync(this.dbPath, 0o600);
860
+ } <span class="branch-0 cbranch-no" title="branch not covered" >catch (err) {</span>
861
+ <span class="cstat-no" title="statement not covered" > // best effort</span>
862
+ <span class="cstat-no" title="statement not covered" > }</span>
863
+ this._migrate();
864
+ this._prepareStatements();
865
+ return this.db;
866
+ } catch (err) {
867
+ this._dbError = err &amp;&amp; err.message ? err.message <span class="branch-0 cbranch-no" title="branch not covered" >: 'failed_to_initialize_callbook_db';</span>
868
+ return null;
869
+ }
870
+ }
871
+ &nbsp;
872
+ _migrate() {
873
+ this.db.exec(`
874
+ PRAGMA journal_mode = WAL;
875
+ &nbsp;
876
+ CREATE TABLE IF NOT EXISTS provision_codes (
877
+ id TEXT PRIMARY KEY,
878
+ code_hash TEXT NOT NULL UNIQUE,
879
+ label TEXT,
880
+ created_at TEXT NOT NULL,
881
+ expires_at TEXT NOT NULL,
882
+ used_at TEXT
883
+ );
884
+ &nbsp;
885
+ CREATE INDEX IF NOT EXISTS idx_provision_codes_expires ON provision_codes(expires_at);
886
+ CREATE INDEX IF NOT EXISTS idx_provision_codes_used ON provision_codes(used_at);
887
+ &nbsp;
888
+ CREATE TABLE IF NOT EXISTS devices (
889
+ id TEXT PRIMARY KEY,
890
+ label TEXT,
891
+ created_at TEXT NOT NULL,
892
+ revoked_at TEXT,
893
+ last_used_at TEXT
894
+ );
895
+ &nbsp;
896
+ CREATE INDEX IF NOT EXISTS idx_devices_revoked ON devices(revoked_at);
897
+ &nbsp;
898
+ CREATE TABLE IF NOT EXISTS sessions (
899
+ id TEXT PRIMARY KEY,
900
+ device_id TEXT NOT NULL,
901
+ token_hash TEXT NOT NULL UNIQUE,
902
+ created_at TEXT NOT NULL,
903
+ revoked_at TEXT,
904
+ last_used_at TEXT,
905
+ FOREIGN KEY(device_id) REFERENCES devices(id)
906
+ );
907
+ &nbsp;
908
+ CREATE INDEX IF NOT EXISTS idx_sessions_device_id ON sessions(device_id);
909
+ CREATE INDEX IF NOT EXISTS idx_sessions_revoked ON sessions(revoked_at);
910
+ `);
911
+ }
912
+ &nbsp;
913
+ _prepareStatements() {
914
+ this._stmts = {
915
+ insertProvision: this.db.prepare(
916
+ `INSERT INTO provision_codes (id, code_hash, label, created_at, expires_at, used_at)
917
+ VALUES (@id, @code_hash, @label, @created_at, @expires_at, NULL)`
918
+ ),
919
+ findProvisionByHash: this.db.prepare(
920
+ `SELECT * FROM provision_codes WHERE code_hash = ?`
921
+ ),
922
+ markProvisionUsed: this.db.prepare(
923
+ `UPDATE provision_codes SET used_at = @used_at WHERE id = @id AND used_at IS NULL`
924
+ ),
925
+ &nbsp;
926
+ insertDevice: this.db.prepare(
927
+ `INSERT INTO devices (id, label, created_at, revoked_at, last_used_at)
928
+ VALUES (@id, @label, @created_at, NULL, NULL)`
929
+ ),
930
+ getDevice: this.db.prepare(
931
+ `SELECT * FROM devices WHERE id = ?`
932
+ ),
933
+ listDevices: this.db.prepare(
934
+ `SELECT
935
+ d.id,
936
+ d.label,
937
+ d.created_at,
938
+ d.revoked_at,
939
+ d.last_used_at,
940
+ (SELECT COUNT(*) FROM sessions s WHERE s.device_id = d.id AND s.revoked_at IS NULL) AS active_sessions
941
+ FROM devices d
942
+ ORDER BY d.created_at DESC
943
+ LIMIT ?`
944
+ ),
945
+ updateDeviceLastUsed: this.db.prepare(
946
+ `UPDATE devices SET last_used_at = ? WHERE id = ?`
947
+ ),
948
+ revokeDevice: this.db.prepare(
949
+ `UPDATE devices SET revoked_at = ? WHERE id = ? AND revoked_at IS NULL`
950
+ ),
951
+ &nbsp;
952
+ insertSession: this.db.prepare(
953
+ `INSERT INTO sessions (id, device_id, token_hash, created_at, revoked_at, last_used_at)
954
+ VALUES (@id, @device_id, @token_hash, @created_at, NULL, NULL)`
955
+ ),
956
+ findSessionByHash: this.db.prepare(
957
+ `SELECT * FROM sessions WHERE token_hash = ?`
958
+ ),
959
+ updateSessionLastUsed: this.db.prepare(
960
+ `UPDATE sessions SET last_used_at = ? WHERE id = ?`
961
+ ),
962
+ revokeSessionsByDevice: this.db.prepare(
963
+ `UPDATE sessions SET revoked_at = ? WHERE device_id = ? AND revoked_at IS NULL`
964
+ )
965
+ };
966
+ }
967
+ &nbsp;
968
+ isAvailable() {
969
+ return Boolean(this._initDb());
970
+ }
971
+ &nbsp;
972
+ getDbError() {
973
+ this._initDb();
974
+ return this._dbError;
975
+ }
976
+ &nbsp;
977
+ /**
978
+ * Create a one-time provisioning code (default TTL: 24 hours).
979
+ * Returns { code, record } where code is plaintext (show once).
980
+ */
981
+ createProvisionCode(options = {}) {
982
+ const db = this._initDb();
983
+ if (!db) {
984
+ return { success: false, error: 'callbook_storage_unavailable', message: this._dbError };
985
+ }
986
+ &nbsp;
987
+ const label = options.label ? String(options.label).trim().slice(0, 120) : null;
988
+ const ttlMs = Number.isFinite(options.ttlMs) ? options.ttlMs : (24 * 60 * 60 * 1000);
989
+ const createdAt = nowIso();
990
+ const expiresAt = new Date(Date.now() + Math.max(1, ttlMs)).toISOString();
991
+ &nbsp;
992
+ const code = randomToken('cbk_');
993
+ const record = {
994
+ id: `cbkprov_${crypto.randomBytes(10).toString('hex')}`,
995
+ code_hash: sha256Hex(code),
996
+ label,
997
+ created_at: createdAt,
998
+ expires_at: expiresAt
999
+ };
1000
+ &nbsp;
1001
+ this._stmts.insertProvision.run(record);
1002
+ &nbsp;
1003
+ return {
1004
+ success: true,
1005
+ code,
1006
+ record: {
1007
+ id: record.id,
1008
+ label: record.label,
1009
+ created_at: record.created_at,
1010
+ expires_at: record.expires_at,
1011
+ used_at: null
1012
+ }
1013
+ };
1014
+ }
1015
+ &nbsp;
1016
+ /**
1017
+ * Exchange a provisioning code for a long-lived session token.
1018
+ * Returns { sessionToken, device } on success.
1019
+ */
1020
+ exchangeProvisionCode(code, options = {}) {
1021
+ const db = this._initDb();
1022
+ if (!db) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
1023
+ <span class="cstat-no" title="statement not covered" > return { success: false, error: 'callbook_storage_unavailable', message: this._dbError };</span>
1024
+ <span class="cstat-no" title="statement not covered" > }</span>
1025
+ &nbsp;
1026
+ const raw = String(code || '').trim();
1027
+ if (!raw) {
1028
+ return { success: false, error: 'missing_code' };
1029
+ }
1030
+ &nbsp;
1031
+ const codeHash = sha256Hex(raw);
1032
+ const found = this._stmts.findProvisionByHash.get(codeHash);
1033
+ if (!found) {
1034
+ return { success: false, error: 'invalid_code' };
1035
+ }
1036
+ &nbsp;
1037
+ const now = Date.now();
1038
+ const expiresMs = Date.parse(found.expires_at);
1039
+ if (Number.isFinite(expiresMs) &amp;&amp; now &gt; expiresMs) {
1040
+ return { success: false, error: 'code_expired' };
1041
+ }
1042
+ if (found.used_at) {
1043
+ return { success: false, error: 'code_already_used' };
1044
+ }
1045
+ &nbsp;
1046
+ const usedAt = nowIso();
1047
+ const tx = db.transaction(() =&gt; {
1048
+ const marked = this._stmts.markProvisionUsed.run({ id: found.id, used_at: usedAt });
1049
+ if (!marked || marked.changes !== 1) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
1050
+ <span class="cstat-no" title="statement not covered" > // Another request raced us.</span>
1051
+ <span class="cstat-no" title="statement not covered" > return { success: false, error: 'code_already_used' };</span>
1052
+ <span class="cstat-no" title="statement not covered" > }</span>
1053
+ &nbsp;
1054
+ const deviceId = `cbkdev_${crypto.randomBytes(10).toString('hex')}`;
1055
+ const deviceLabel = (options.label ? String(options.label).trim().slice(0, 120) : null) || found.label || null;
1056
+ this._stmts.insertDevice.run({
1057
+ id: deviceId,
1058
+ label: deviceLabel,
1059
+ created_at: usedAt
1060
+ });
1061
+ &nbsp;
1062
+ const sessionToken = randomToken('cbksess_');
1063
+ const sessionId = `cbks_${crypto.randomBytes(10).toString('hex')}`;
1064
+ this._stmts.insertSession.run({
1065
+ id: sessionId,
1066
+ device_id: deviceId,
1067
+ token_hash: sha256Hex(sessionToken),
1068
+ created_at: usedAt
1069
+ });
1070
+ &nbsp;
1071
+ return {
1072
+ success: true,
1073
+ sessionToken,
1074
+ device: {
1075
+ id: deviceId,
1076
+ label: deviceLabel,
1077
+ created_at: usedAt,
1078
+ revoked_at: null,
1079
+ last_used_at: null
1080
+ }
1081
+ };
1082
+ });
1083
+ &nbsp;
1084
+ return tx();
1085
+ }
1086
+ &nbsp;
1087
+ /**
1088
+ * Validate a session token from a cookie.
1089
+ * Returns { valid, session, device }.
1090
+ */
1091
+ validateSession(sessionToken) {
1092
+ const db = this._initDb();
1093
+ if (!db) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
1094
+ <span class="cstat-no" title="statement not covered" > return { valid: false, error: 'callbook_storage_unavailable' };</span>
1095
+ <span class="cstat-no" title="statement not covered" > }</span>
1096
+ &nbsp;
1097
+ const raw = String(sessionToken || '').trim();
1098
+ if (!raw) return { valid: false, error: 'missing_session' };
1099
+ &nbsp;
1100
+ const session = this._stmts.findSessionByHash.get(sha256Hex(raw));
1101
+ if (!session) return { valid: false, error: 'invalid_session' };
1102
+ if (session.revoked_at) return { valid: false, error: 'session_revoked' };
1103
+ &nbsp;
1104
+ const device = this._stmts.getDevice.get(session.device_id);
1105
+ if (!device) <span class="branch-0 cbranch-no" title="branch not covered" >return { valid: false, error: 'device_not_found' };</span>
1106
+ if (device.revoked_at) <span class="branch-0 cbranch-no" title="branch not covered" >return { valid: false, error: 'device_revoked' };</span>
1107
+ &nbsp;
1108
+ const usedAt = nowIso();
1109
+ try {
1110
+ this._stmts.updateSessionLastUsed.run(usedAt, session.id);
1111
+ this._stmts.updateDeviceLastUsed.run(usedAt, device.id);
1112
+ } <span class="branch-0 cbranch-no" title="branch not covered" >catch (err) {</span>
1113
+ <span class="cstat-no" title="statement not covered" > // best effort</span>
1114
+ <span class="cstat-no" title="statement not covered" > }</span>
1115
+ &nbsp;
1116
+ return { valid: true, session: { id: session.id, device_id: session.device_id }, device };
1117
+ }
1118
+ &nbsp;
1119
+ listDevices(options = {}) {
1120
+ const db = this._initDb();
1121
+ if (!db) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
1122
+ <span class="cstat-no" title="statement not covered" > return { success: false, error: 'callbook_storage_unavailable', message: this._dbError, devices: [] };</span>
1123
+ <span class="cstat-no" title="statement not covered" > }</span>
1124
+ const limit = Math.min(500, Math.max(1, Number.parseInt(String(options.limit || '200'), 10) <span class="branch-0 cbranch-no" title="branch not covered" >|| 200)</span>);
1125
+ const rows = this._stmts.listDevices.all(limit);
1126
+ const includeRevoked = Boolean(options.includeRevoked);
1127
+ const devices = includeRevoked ? rows : rows.filter(r =&gt; !r.revoked_at);
1128
+ return { success: true, devices };
1129
+ }
1130
+ &nbsp;
1131
+ revokeDevice(deviceId) {
1132
+ const db = this._initDb();
1133
+ if (!db) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
1134
+ <span class="cstat-no" title="statement not covered" > return { success: false, error: 'callbook_storage_unavailable', message: this._dbError };</span>
1135
+ <span class="cstat-no" title="statement not covered" > }</span>
1136
+ const id = String(deviceId || '').trim();
1137
+ if (!id) return { success: false, error: 'device_id_required' };
1138
+ const revokedAt = nowIso();
1139
+ const tx = db.transaction(() =&gt; {
1140
+ const dev = this._stmts.getDevice.get(id);
1141
+ if (!dev) return { success: false, error: 'device_not_found' };
1142
+ this._stmts.revokeDevice.run(revokedAt, id);
1143
+ this._stmts.revokeSessionsByDevice.run(revokedAt, id);
1144
+ return { success: true, device: { ...dev, revoked_at: revokedAt } };
1145
+ });
1146
+ return tx();
1147
+ }
1148
+ &nbsp;
1149
+ // A2A-57: Close the SQLite database and flush WAL on shutdown
1150
+ close() {
1151
+ if (this.db) {
1152
+ try { this.db.close(); } <span class="branch-0 cbranch-no" title="branch not covered" >catch (_) {}</span>
1153
+ this.db = null;
1154
+ }
1155
+ }
1156
+ }
1157
+ &nbsp;
1158
+ module.exports = {
1159
+ DEFAULT_CONFIG_DIR,
1160
+ DB_FILENAME,
1161
+ CallbookStore
1162
+ };
1163
+ &nbsp;
1164
+ &nbsp;</pre></td></tr></table></pre>
1165
+
1166
+ <div class='push'></div><!-- for sticky footer -->
1167
+ </div><!-- /wrapper -->
1168
+ <div class='footer quiet pad2 space-top1 center small'>
1169
+ Code coverage generated by
1170
+ <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
1171
+ at 2026-03-03T22:25:10.857Z
1172
+ </div>
1173
+ <script src="../../prettify.js"></script>
1174
+ <script>
1175
+ window.onload = function () {
1176
+ prettyPrint();
1177
+ };
1178
+ </script>
1179
+ <script src="../../sorter.js"></script>
1180
+ <script src="../../block-navigation.js"></script>
1181
+ </body>
1182
+ </html>
1183
+