floatnote 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/.beads/config.json +6 -0
  2. package/.beads/issues/floatnote-1.md +21 -0
  3. package/.beads/issues/floatnote-10.md +28 -0
  4. package/.beads/issues/floatnote-11.md +36 -0
  5. package/.beads/issues/floatnote-12.md +25 -0
  6. package/.beads/issues/floatnote-13.md +37 -0
  7. package/.beads/issues/floatnote-14.md +22 -0
  8. package/.beads/issues/floatnote-15.md +22 -0
  9. package/.beads/issues/floatnote-16.md +20 -0
  10. package/.beads/issues/floatnote-17.md +20 -0
  11. package/.beads/issues/floatnote-18.md +21 -0
  12. package/.beads/issues/floatnote-19.md +19 -0
  13. package/.beads/issues/floatnote-2.md +32 -0
  14. package/.beads/issues/floatnote-20.md +22 -0
  15. package/.beads/issues/floatnote-3.md +50 -0
  16. package/.beads/issues/floatnote-4.md +31 -0
  17. package/.beads/issues/floatnote-5.md +28 -0
  18. package/.beads/issues/floatnote-6.md +30 -0
  19. package/.beads/issues/floatnote-7.md +38 -0
  20. package/.beads/issues/floatnote-8.md +29 -0
  21. package/.beads/issues/floatnote-9.md +32 -0
  22. package/CLAUDE.md +61 -0
  23. package/README.md +95 -0
  24. package/bin/floatnote.js +218 -0
  25. package/coverage/base.css +224 -0
  26. package/coverage/bin/floatnote.js.html +739 -0
  27. package/coverage/bin/index.html +116 -0
  28. package/coverage/block-navigation.js +87 -0
  29. package/coverage/favicon.png +0 -0
  30. package/coverage/index.html +131 -0
  31. package/coverage/lcov-report/base.css +224 -0
  32. package/coverage/lcov-report/bin/floatnote.js.html +739 -0
  33. package/coverage/lcov-report/bin/index.html +116 -0
  34. package/coverage/lcov-report/block-navigation.js +87 -0
  35. package/coverage/lcov-report/favicon.png +0 -0
  36. package/coverage/lcov-report/index.html +131 -0
  37. package/coverage/lcov-report/prettify.css +1 -0
  38. package/coverage/lcov-report/prettify.js +2 -0
  39. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  40. package/coverage/lcov-report/sorter.js +210 -0
  41. package/coverage/lcov-report/src/index.html +146 -0
  42. package/coverage/lcov-report/src/main.js.html +1483 -0
  43. package/coverage/lcov-report/src/preload.js.html +361 -0
  44. package/coverage/lcov-report/src/renderer.js.html +8767 -0
  45. package/coverage/lcov.info +3273 -0
  46. package/coverage/prettify.css +1 -0
  47. package/coverage/prettify.js +2 -0
  48. package/coverage/sort-arrow-sprite.png +0 -0
  49. package/coverage/sorter.js +210 -0
  50. package/coverage/src/index.html +146 -0
  51. package/coverage/src/main.js.html +1483 -0
  52. package/coverage/src/preload.js.html +361 -0
  53. package/coverage/src/renderer.js.html +8767 -0
  54. package/jest.config.js +48 -0
  55. package/package.json +59 -0
  56. package/src/icon-template.png +0 -0
  57. package/src/index.html +296 -0
  58. package/src/main.js +494 -0
  59. package/src/preload.js +96 -0
  60. package/src/renderer.js +3203 -0
  61. package/src/styles.css +1448 -0
  62. package/tests/cli/floatnote.test.js +167 -0
  63. package/tests/main/main.test.js +287 -0
  64. package/tests/mocks/electron.js +126 -0
  65. package/tests/mocks/fs.js +17 -0
  66. package/tests/preload/preload.test.js +218 -0
  67. package/tests/renderer/history.test.js +234 -0
  68. package/tests/renderer/notes.test.js +262 -0
  69. package/tests/renderer/settings.test.js +178 -0
@@ -0,0 +1,1483 @@
1
+
2
+ <!doctype html>
3
+ <html lang="en">
4
+
5
+ <head>
6
+ <title>Code coverage report for src/main.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</a> main.js</h1>
23
+ <div class='clearfix'>
24
+
25
+ <div class='fl pad1y space-right2'>
26
+ <span class="strong">0% </span>
27
+ <span class="quiet">Statements</span>
28
+ <span class='fraction'>0/200</span>
29
+ </div>
30
+
31
+
32
+ <div class='fl pad1y space-right2'>
33
+ <span class="strong">0% </span>
34
+ <span class="quiet">Branches</span>
35
+ <span class='fraction'>0/77</span>
36
+ </div>
37
+
38
+
39
+ <div class='fl pad1y space-right2'>
40
+ <span class="strong">0% </span>
41
+ <span class="quiet">Functions</span>
42
+ <span class='fraction'>0/31</span>
43
+ </div>
44
+
45
+
46
+ <div class='fl pad1y space-right2'>
47
+ <span class="strong">0% </span>
48
+ <span class="quiet">Lines</span>
49
+ <span class='fraction'>0/196</span>
50
+ </div>
51
+
52
+
53
+ </div>
54
+ <p class="quiet">
55
+ Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block.
56
+ </p>
57
+ <template id="filterTemplate">
58
+ <div class="quiet">
59
+ Filter:
60
+ <input type="search" id="fileSearch">
61
+ </div>
62
+ </template>
63
+ </div>
64
+ <div class='status-line low'></div>
65
+ <pre><table class="coverage">
66
+ <tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
67
+ <a name='L2'></a><a href='#L2'>2</a>
68
+ <a name='L3'></a><a href='#L3'>3</a>
69
+ <a name='L4'></a><a href='#L4'>4</a>
70
+ <a name='L5'></a><a href='#L5'>5</a>
71
+ <a name='L6'></a><a href='#L6'>6</a>
72
+ <a name='L7'></a><a href='#L7'>7</a>
73
+ <a name='L8'></a><a href='#L8'>8</a>
74
+ <a name='L9'></a><a href='#L9'>9</a>
75
+ <a name='L10'></a><a href='#L10'>10</a>
76
+ <a name='L11'></a><a href='#L11'>11</a>
77
+ <a name='L12'></a><a href='#L12'>12</a>
78
+ <a name='L13'></a><a href='#L13'>13</a>
79
+ <a name='L14'></a><a href='#L14'>14</a>
80
+ <a name='L15'></a><a href='#L15'>15</a>
81
+ <a name='L16'></a><a href='#L16'>16</a>
82
+ <a name='L17'></a><a href='#L17'>17</a>
83
+ <a name='L18'></a><a href='#L18'>18</a>
84
+ <a name='L19'></a><a href='#L19'>19</a>
85
+ <a name='L20'></a><a href='#L20'>20</a>
86
+ <a name='L21'></a><a href='#L21'>21</a>
87
+ <a name='L22'></a><a href='#L22'>22</a>
88
+ <a name='L23'></a><a href='#L23'>23</a>
89
+ <a name='L24'></a><a href='#L24'>24</a>
90
+ <a name='L25'></a><a href='#L25'>25</a>
91
+ <a name='L26'></a><a href='#L26'>26</a>
92
+ <a name='L27'></a><a href='#L27'>27</a>
93
+ <a name='L28'></a><a href='#L28'>28</a>
94
+ <a name='L29'></a><a href='#L29'>29</a>
95
+ <a name='L30'></a><a href='#L30'>30</a>
96
+ <a name='L31'></a><a href='#L31'>31</a>
97
+ <a name='L32'></a><a href='#L32'>32</a>
98
+ <a name='L33'></a><a href='#L33'>33</a>
99
+ <a name='L34'></a><a href='#L34'>34</a>
100
+ <a name='L35'></a><a href='#L35'>35</a>
101
+ <a name='L36'></a><a href='#L36'>36</a>
102
+ <a name='L37'></a><a href='#L37'>37</a>
103
+ <a name='L38'></a><a href='#L38'>38</a>
104
+ <a name='L39'></a><a href='#L39'>39</a>
105
+ <a name='L40'></a><a href='#L40'>40</a>
106
+ <a name='L41'></a><a href='#L41'>41</a>
107
+ <a name='L42'></a><a href='#L42'>42</a>
108
+ <a name='L43'></a><a href='#L43'>43</a>
109
+ <a name='L44'></a><a href='#L44'>44</a>
110
+ <a name='L45'></a><a href='#L45'>45</a>
111
+ <a name='L46'></a><a href='#L46'>46</a>
112
+ <a name='L47'></a><a href='#L47'>47</a>
113
+ <a name='L48'></a><a href='#L48'>48</a>
114
+ <a name='L49'></a><a href='#L49'>49</a>
115
+ <a name='L50'></a><a href='#L50'>50</a>
116
+ <a name='L51'></a><a href='#L51'>51</a>
117
+ <a name='L52'></a><a href='#L52'>52</a>
118
+ <a name='L53'></a><a href='#L53'>53</a>
119
+ <a name='L54'></a><a href='#L54'>54</a>
120
+ <a name='L55'></a><a href='#L55'>55</a>
121
+ <a name='L56'></a><a href='#L56'>56</a>
122
+ <a name='L57'></a><a href='#L57'>57</a>
123
+ <a name='L58'></a><a href='#L58'>58</a>
124
+ <a name='L59'></a><a href='#L59'>59</a>
125
+ <a name='L60'></a><a href='#L60'>60</a>
126
+ <a name='L61'></a><a href='#L61'>61</a>
127
+ <a name='L62'></a><a href='#L62'>62</a>
128
+ <a name='L63'></a><a href='#L63'>63</a>
129
+ <a name='L64'></a><a href='#L64'>64</a>
130
+ <a name='L65'></a><a href='#L65'>65</a>
131
+ <a name='L66'></a><a href='#L66'>66</a>
132
+ <a name='L67'></a><a href='#L67'>67</a>
133
+ <a name='L68'></a><a href='#L68'>68</a>
134
+ <a name='L69'></a><a href='#L69'>69</a>
135
+ <a name='L70'></a><a href='#L70'>70</a>
136
+ <a name='L71'></a><a href='#L71'>71</a>
137
+ <a name='L72'></a><a href='#L72'>72</a>
138
+ <a name='L73'></a><a href='#L73'>73</a>
139
+ <a name='L74'></a><a href='#L74'>74</a>
140
+ <a name='L75'></a><a href='#L75'>75</a>
141
+ <a name='L76'></a><a href='#L76'>76</a>
142
+ <a name='L77'></a><a href='#L77'>77</a>
143
+ <a name='L78'></a><a href='#L78'>78</a>
144
+ <a name='L79'></a><a href='#L79'>79</a>
145
+ <a name='L80'></a><a href='#L80'>80</a>
146
+ <a name='L81'></a><a href='#L81'>81</a>
147
+ <a name='L82'></a><a href='#L82'>82</a>
148
+ <a name='L83'></a><a href='#L83'>83</a>
149
+ <a name='L84'></a><a href='#L84'>84</a>
150
+ <a name='L85'></a><a href='#L85'>85</a>
151
+ <a name='L86'></a><a href='#L86'>86</a>
152
+ <a name='L87'></a><a href='#L87'>87</a>
153
+ <a name='L88'></a><a href='#L88'>88</a>
154
+ <a name='L89'></a><a href='#L89'>89</a>
155
+ <a name='L90'></a><a href='#L90'>90</a>
156
+ <a name='L91'></a><a href='#L91'>91</a>
157
+ <a name='L92'></a><a href='#L92'>92</a>
158
+ <a name='L93'></a><a href='#L93'>93</a>
159
+ <a name='L94'></a><a href='#L94'>94</a>
160
+ <a name='L95'></a><a href='#L95'>95</a>
161
+ <a name='L96'></a><a href='#L96'>96</a>
162
+ <a name='L97'></a><a href='#L97'>97</a>
163
+ <a name='L98'></a><a href='#L98'>98</a>
164
+ <a name='L99'></a><a href='#L99'>99</a>
165
+ <a name='L100'></a><a href='#L100'>100</a>
166
+ <a name='L101'></a><a href='#L101'>101</a>
167
+ <a name='L102'></a><a href='#L102'>102</a>
168
+ <a name='L103'></a><a href='#L103'>103</a>
169
+ <a name='L104'></a><a href='#L104'>104</a>
170
+ <a name='L105'></a><a href='#L105'>105</a>
171
+ <a name='L106'></a><a href='#L106'>106</a>
172
+ <a name='L107'></a><a href='#L107'>107</a>
173
+ <a name='L108'></a><a href='#L108'>108</a>
174
+ <a name='L109'></a><a href='#L109'>109</a>
175
+ <a name='L110'></a><a href='#L110'>110</a>
176
+ <a name='L111'></a><a href='#L111'>111</a>
177
+ <a name='L112'></a><a href='#L112'>112</a>
178
+ <a name='L113'></a><a href='#L113'>113</a>
179
+ <a name='L114'></a><a href='#L114'>114</a>
180
+ <a name='L115'></a><a href='#L115'>115</a>
181
+ <a name='L116'></a><a href='#L116'>116</a>
182
+ <a name='L117'></a><a href='#L117'>117</a>
183
+ <a name='L118'></a><a href='#L118'>118</a>
184
+ <a name='L119'></a><a href='#L119'>119</a>
185
+ <a name='L120'></a><a href='#L120'>120</a>
186
+ <a name='L121'></a><a href='#L121'>121</a>
187
+ <a name='L122'></a><a href='#L122'>122</a>
188
+ <a name='L123'></a><a href='#L123'>123</a>
189
+ <a name='L124'></a><a href='#L124'>124</a>
190
+ <a name='L125'></a><a href='#L125'>125</a>
191
+ <a name='L126'></a><a href='#L126'>126</a>
192
+ <a name='L127'></a><a href='#L127'>127</a>
193
+ <a name='L128'></a><a href='#L128'>128</a>
194
+ <a name='L129'></a><a href='#L129'>129</a>
195
+ <a name='L130'></a><a href='#L130'>130</a>
196
+ <a name='L131'></a><a href='#L131'>131</a>
197
+ <a name='L132'></a><a href='#L132'>132</a>
198
+ <a name='L133'></a><a href='#L133'>133</a>
199
+ <a name='L134'></a><a href='#L134'>134</a>
200
+ <a name='L135'></a><a href='#L135'>135</a>
201
+ <a name='L136'></a><a href='#L136'>136</a>
202
+ <a name='L137'></a><a href='#L137'>137</a>
203
+ <a name='L138'></a><a href='#L138'>138</a>
204
+ <a name='L139'></a><a href='#L139'>139</a>
205
+ <a name='L140'></a><a href='#L140'>140</a>
206
+ <a name='L141'></a><a href='#L141'>141</a>
207
+ <a name='L142'></a><a href='#L142'>142</a>
208
+ <a name='L143'></a><a href='#L143'>143</a>
209
+ <a name='L144'></a><a href='#L144'>144</a>
210
+ <a name='L145'></a><a href='#L145'>145</a>
211
+ <a name='L146'></a><a href='#L146'>146</a>
212
+ <a name='L147'></a><a href='#L147'>147</a>
213
+ <a name='L148'></a><a href='#L148'>148</a>
214
+ <a name='L149'></a><a href='#L149'>149</a>
215
+ <a name='L150'></a><a href='#L150'>150</a>
216
+ <a name='L151'></a><a href='#L151'>151</a>
217
+ <a name='L152'></a><a href='#L152'>152</a>
218
+ <a name='L153'></a><a href='#L153'>153</a>
219
+ <a name='L154'></a><a href='#L154'>154</a>
220
+ <a name='L155'></a><a href='#L155'>155</a>
221
+ <a name='L156'></a><a href='#L156'>156</a>
222
+ <a name='L157'></a><a href='#L157'>157</a>
223
+ <a name='L158'></a><a href='#L158'>158</a>
224
+ <a name='L159'></a><a href='#L159'>159</a>
225
+ <a name='L160'></a><a href='#L160'>160</a>
226
+ <a name='L161'></a><a href='#L161'>161</a>
227
+ <a name='L162'></a><a href='#L162'>162</a>
228
+ <a name='L163'></a><a href='#L163'>163</a>
229
+ <a name='L164'></a><a href='#L164'>164</a>
230
+ <a name='L165'></a><a href='#L165'>165</a>
231
+ <a name='L166'></a><a href='#L166'>166</a>
232
+ <a name='L167'></a><a href='#L167'>167</a>
233
+ <a name='L168'></a><a href='#L168'>168</a>
234
+ <a name='L169'></a><a href='#L169'>169</a>
235
+ <a name='L170'></a><a href='#L170'>170</a>
236
+ <a name='L171'></a><a href='#L171'>171</a>
237
+ <a name='L172'></a><a href='#L172'>172</a>
238
+ <a name='L173'></a><a href='#L173'>173</a>
239
+ <a name='L174'></a><a href='#L174'>174</a>
240
+ <a name='L175'></a><a href='#L175'>175</a>
241
+ <a name='L176'></a><a href='#L176'>176</a>
242
+ <a name='L177'></a><a href='#L177'>177</a>
243
+ <a name='L178'></a><a href='#L178'>178</a>
244
+ <a name='L179'></a><a href='#L179'>179</a>
245
+ <a name='L180'></a><a href='#L180'>180</a>
246
+ <a name='L181'></a><a href='#L181'>181</a>
247
+ <a name='L182'></a><a href='#L182'>182</a>
248
+ <a name='L183'></a><a href='#L183'>183</a>
249
+ <a name='L184'></a><a href='#L184'>184</a>
250
+ <a name='L185'></a><a href='#L185'>185</a>
251
+ <a name='L186'></a><a href='#L186'>186</a>
252
+ <a name='L187'></a><a href='#L187'>187</a>
253
+ <a name='L188'></a><a href='#L188'>188</a>
254
+ <a name='L189'></a><a href='#L189'>189</a>
255
+ <a name='L190'></a><a href='#L190'>190</a>
256
+ <a name='L191'></a><a href='#L191'>191</a>
257
+ <a name='L192'></a><a href='#L192'>192</a>
258
+ <a name='L193'></a><a href='#L193'>193</a>
259
+ <a name='L194'></a><a href='#L194'>194</a>
260
+ <a name='L195'></a><a href='#L195'>195</a>
261
+ <a name='L196'></a><a href='#L196'>196</a>
262
+ <a name='L197'></a><a href='#L197'>197</a>
263
+ <a name='L198'></a><a href='#L198'>198</a>
264
+ <a name='L199'></a><a href='#L199'>199</a>
265
+ <a name='L200'></a><a href='#L200'>200</a>
266
+ <a name='L201'></a><a href='#L201'>201</a>
267
+ <a name='L202'></a><a href='#L202'>202</a>
268
+ <a name='L203'></a><a href='#L203'>203</a>
269
+ <a name='L204'></a><a href='#L204'>204</a>
270
+ <a name='L205'></a><a href='#L205'>205</a>
271
+ <a name='L206'></a><a href='#L206'>206</a>
272
+ <a name='L207'></a><a href='#L207'>207</a>
273
+ <a name='L208'></a><a href='#L208'>208</a>
274
+ <a name='L209'></a><a href='#L209'>209</a>
275
+ <a name='L210'></a><a href='#L210'>210</a>
276
+ <a name='L211'></a><a href='#L211'>211</a>
277
+ <a name='L212'></a><a href='#L212'>212</a>
278
+ <a name='L213'></a><a href='#L213'>213</a>
279
+ <a name='L214'></a><a href='#L214'>214</a>
280
+ <a name='L215'></a><a href='#L215'>215</a>
281
+ <a name='L216'></a><a href='#L216'>216</a>
282
+ <a name='L217'></a><a href='#L217'>217</a>
283
+ <a name='L218'></a><a href='#L218'>218</a>
284
+ <a name='L219'></a><a href='#L219'>219</a>
285
+ <a name='L220'></a><a href='#L220'>220</a>
286
+ <a name='L221'></a><a href='#L221'>221</a>
287
+ <a name='L222'></a><a href='#L222'>222</a>
288
+ <a name='L223'></a><a href='#L223'>223</a>
289
+ <a name='L224'></a><a href='#L224'>224</a>
290
+ <a name='L225'></a><a href='#L225'>225</a>
291
+ <a name='L226'></a><a href='#L226'>226</a>
292
+ <a name='L227'></a><a href='#L227'>227</a>
293
+ <a name='L228'></a><a href='#L228'>228</a>
294
+ <a name='L229'></a><a href='#L229'>229</a>
295
+ <a name='L230'></a><a href='#L230'>230</a>
296
+ <a name='L231'></a><a href='#L231'>231</a>
297
+ <a name='L232'></a><a href='#L232'>232</a>
298
+ <a name='L233'></a><a href='#L233'>233</a>
299
+ <a name='L234'></a><a href='#L234'>234</a>
300
+ <a name='L235'></a><a href='#L235'>235</a>
301
+ <a name='L236'></a><a href='#L236'>236</a>
302
+ <a name='L237'></a><a href='#L237'>237</a>
303
+ <a name='L238'></a><a href='#L238'>238</a>
304
+ <a name='L239'></a><a href='#L239'>239</a>
305
+ <a name='L240'></a><a href='#L240'>240</a>
306
+ <a name='L241'></a><a href='#L241'>241</a>
307
+ <a name='L242'></a><a href='#L242'>242</a>
308
+ <a name='L243'></a><a href='#L243'>243</a>
309
+ <a name='L244'></a><a href='#L244'>244</a>
310
+ <a name='L245'></a><a href='#L245'>245</a>
311
+ <a name='L246'></a><a href='#L246'>246</a>
312
+ <a name='L247'></a><a href='#L247'>247</a>
313
+ <a name='L248'></a><a href='#L248'>248</a>
314
+ <a name='L249'></a><a href='#L249'>249</a>
315
+ <a name='L250'></a><a href='#L250'>250</a>
316
+ <a name='L251'></a><a href='#L251'>251</a>
317
+ <a name='L252'></a><a href='#L252'>252</a>
318
+ <a name='L253'></a><a href='#L253'>253</a>
319
+ <a name='L254'></a><a href='#L254'>254</a>
320
+ <a name='L255'></a><a href='#L255'>255</a>
321
+ <a name='L256'></a><a href='#L256'>256</a>
322
+ <a name='L257'></a><a href='#L257'>257</a>
323
+ <a name='L258'></a><a href='#L258'>258</a>
324
+ <a name='L259'></a><a href='#L259'>259</a>
325
+ <a name='L260'></a><a href='#L260'>260</a>
326
+ <a name='L261'></a><a href='#L261'>261</a>
327
+ <a name='L262'></a><a href='#L262'>262</a>
328
+ <a name='L263'></a><a href='#L263'>263</a>
329
+ <a name='L264'></a><a href='#L264'>264</a>
330
+ <a name='L265'></a><a href='#L265'>265</a>
331
+ <a name='L266'></a><a href='#L266'>266</a>
332
+ <a name='L267'></a><a href='#L267'>267</a>
333
+ <a name='L268'></a><a href='#L268'>268</a>
334
+ <a name='L269'></a><a href='#L269'>269</a>
335
+ <a name='L270'></a><a href='#L270'>270</a>
336
+ <a name='L271'></a><a href='#L271'>271</a>
337
+ <a name='L272'></a><a href='#L272'>272</a>
338
+ <a name='L273'></a><a href='#L273'>273</a>
339
+ <a name='L274'></a><a href='#L274'>274</a>
340
+ <a name='L275'></a><a href='#L275'>275</a>
341
+ <a name='L276'></a><a href='#L276'>276</a>
342
+ <a name='L277'></a><a href='#L277'>277</a>
343
+ <a name='L278'></a><a href='#L278'>278</a>
344
+ <a name='L279'></a><a href='#L279'>279</a>
345
+ <a name='L280'></a><a href='#L280'>280</a>
346
+ <a name='L281'></a><a href='#L281'>281</a>
347
+ <a name='L282'></a><a href='#L282'>282</a>
348
+ <a name='L283'></a><a href='#L283'>283</a>
349
+ <a name='L284'></a><a href='#L284'>284</a>
350
+ <a name='L285'></a><a href='#L285'>285</a>
351
+ <a name='L286'></a><a href='#L286'>286</a>
352
+ <a name='L287'></a><a href='#L287'>287</a>
353
+ <a name='L288'></a><a href='#L288'>288</a>
354
+ <a name='L289'></a><a href='#L289'>289</a>
355
+ <a name='L290'></a><a href='#L290'>290</a>
356
+ <a name='L291'></a><a href='#L291'>291</a>
357
+ <a name='L292'></a><a href='#L292'>292</a>
358
+ <a name='L293'></a><a href='#L293'>293</a>
359
+ <a name='L294'></a><a href='#L294'>294</a>
360
+ <a name='L295'></a><a href='#L295'>295</a>
361
+ <a name='L296'></a><a href='#L296'>296</a>
362
+ <a name='L297'></a><a href='#L297'>297</a>
363
+ <a name='L298'></a><a href='#L298'>298</a>
364
+ <a name='L299'></a><a href='#L299'>299</a>
365
+ <a name='L300'></a><a href='#L300'>300</a>
366
+ <a name='L301'></a><a href='#L301'>301</a>
367
+ <a name='L302'></a><a href='#L302'>302</a>
368
+ <a name='L303'></a><a href='#L303'>303</a>
369
+ <a name='L304'></a><a href='#L304'>304</a>
370
+ <a name='L305'></a><a href='#L305'>305</a>
371
+ <a name='L306'></a><a href='#L306'>306</a>
372
+ <a name='L307'></a><a href='#L307'>307</a>
373
+ <a name='L308'></a><a href='#L308'>308</a>
374
+ <a name='L309'></a><a href='#L309'>309</a>
375
+ <a name='L310'></a><a href='#L310'>310</a>
376
+ <a name='L311'></a><a href='#L311'>311</a>
377
+ <a name='L312'></a><a href='#L312'>312</a>
378
+ <a name='L313'></a><a href='#L313'>313</a>
379
+ <a name='L314'></a><a href='#L314'>314</a>
380
+ <a name='L315'></a><a href='#L315'>315</a>
381
+ <a name='L316'></a><a href='#L316'>316</a>
382
+ <a name='L317'></a><a href='#L317'>317</a>
383
+ <a name='L318'></a><a href='#L318'>318</a>
384
+ <a name='L319'></a><a href='#L319'>319</a>
385
+ <a name='L320'></a><a href='#L320'>320</a>
386
+ <a name='L321'></a><a href='#L321'>321</a>
387
+ <a name='L322'></a><a href='#L322'>322</a>
388
+ <a name='L323'></a><a href='#L323'>323</a>
389
+ <a name='L324'></a><a href='#L324'>324</a>
390
+ <a name='L325'></a><a href='#L325'>325</a>
391
+ <a name='L326'></a><a href='#L326'>326</a>
392
+ <a name='L327'></a><a href='#L327'>327</a>
393
+ <a name='L328'></a><a href='#L328'>328</a>
394
+ <a name='L329'></a><a href='#L329'>329</a>
395
+ <a name='L330'></a><a href='#L330'>330</a>
396
+ <a name='L331'></a><a href='#L331'>331</a>
397
+ <a name='L332'></a><a href='#L332'>332</a>
398
+ <a name='L333'></a><a href='#L333'>333</a>
399
+ <a name='L334'></a><a href='#L334'>334</a>
400
+ <a name='L335'></a><a href='#L335'>335</a>
401
+ <a name='L336'></a><a href='#L336'>336</a>
402
+ <a name='L337'></a><a href='#L337'>337</a>
403
+ <a name='L338'></a><a href='#L338'>338</a>
404
+ <a name='L339'></a><a href='#L339'>339</a>
405
+ <a name='L340'></a><a href='#L340'>340</a>
406
+ <a name='L341'></a><a href='#L341'>341</a>
407
+ <a name='L342'></a><a href='#L342'>342</a>
408
+ <a name='L343'></a><a href='#L343'>343</a>
409
+ <a name='L344'></a><a href='#L344'>344</a>
410
+ <a name='L345'></a><a href='#L345'>345</a>
411
+ <a name='L346'></a><a href='#L346'>346</a>
412
+ <a name='L347'></a><a href='#L347'>347</a>
413
+ <a name='L348'></a><a href='#L348'>348</a>
414
+ <a name='L349'></a><a href='#L349'>349</a>
415
+ <a name='L350'></a><a href='#L350'>350</a>
416
+ <a name='L351'></a><a href='#L351'>351</a>
417
+ <a name='L352'></a><a href='#L352'>352</a>
418
+ <a name='L353'></a><a href='#L353'>353</a>
419
+ <a name='L354'></a><a href='#L354'>354</a>
420
+ <a name='L355'></a><a href='#L355'>355</a>
421
+ <a name='L356'></a><a href='#L356'>356</a>
422
+ <a name='L357'></a><a href='#L357'>357</a>
423
+ <a name='L358'></a><a href='#L358'>358</a>
424
+ <a name='L359'></a><a href='#L359'>359</a>
425
+ <a name='L360'></a><a href='#L360'>360</a>
426
+ <a name='L361'></a><a href='#L361'>361</a>
427
+ <a name='L362'></a><a href='#L362'>362</a>
428
+ <a name='L363'></a><a href='#L363'>363</a>
429
+ <a name='L364'></a><a href='#L364'>364</a>
430
+ <a name='L365'></a><a href='#L365'>365</a>
431
+ <a name='L366'></a><a href='#L366'>366</a>
432
+ <a name='L367'></a><a href='#L367'>367</a>
433
+ <a name='L368'></a><a href='#L368'>368</a>
434
+ <a name='L369'></a><a href='#L369'>369</a>
435
+ <a name='L370'></a><a href='#L370'>370</a>
436
+ <a name='L371'></a><a href='#L371'>371</a>
437
+ <a name='L372'></a><a href='#L372'>372</a>
438
+ <a name='L373'></a><a href='#L373'>373</a>
439
+ <a name='L374'></a><a href='#L374'>374</a>
440
+ <a name='L375'></a><a href='#L375'>375</a>
441
+ <a name='L376'></a><a href='#L376'>376</a>
442
+ <a name='L377'></a><a href='#L377'>377</a>
443
+ <a name='L378'></a><a href='#L378'>378</a>
444
+ <a name='L379'></a><a href='#L379'>379</a>
445
+ <a name='L380'></a><a href='#L380'>380</a>
446
+ <a name='L381'></a><a href='#L381'>381</a>
447
+ <a name='L382'></a><a href='#L382'>382</a>
448
+ <a name='L383'></a><a href='#L383'>383</a>
449
+ <a name='L384'></a><a href='#L384'>384</a>
450
+ <a name='L385'></a><a href='#L385'>385</a>
451
+ <a name='L386'></a><a href='#L386'>386</a>
452
+ <a name='L387'></a><a href='#L387'>387</a>
453
+ <a name='L388'></a><a href='#L388'>388</a>
454
+ <a name='L389'></a><a href='#L389'>389</a>
455
+ <a name='L390'></a><a href='#L390'>390</a>
456
+ <a name='L391'></a><a href='#L391'>391</a>
457
+ <a name='L392'></a><a href='#L392'>392</a>
458
+ <a name='L393'></a><a href='#L393'>393</a>
459
+ <a name='L394'></a><a href='#L394'>394</a>
460
+ <a name='L395'></a><a href='#L395'>395</a>
461
+ <a name='L396'></a><a href='#L396'>396</a>
462
+ <a name='L397'></a><a href='#L397'>397</a>
463
+ <a name='L398'></a><a href='#L398'>398</a>
464
+ <a name='L399'></a><a href='#L399'>399</a>
465
+ <a name='L400'></a><a href='#L400'>400</a>
466
+ <a name='L401'></a><a href='#L401'>401</a>
467
+ <a name='L402'></a><a href='#L402'>402</a>
468
+ <a name='L403'></a><a href='#L403'>403</a>
469
+ <a name='L404'></a><a href='#L404'>404</a>
470
+ <a name='L405'></a><a href='#L405'>405</a>
471
+ <a name='L406'></a><a href='#L406'>406</a>
472
+ <a name='L407'></a><a href='#L407'>407</a>
473
+ <a name='L408'></a><a href='#L408'>408</a>
474
+ <a name='L409'></a><a href='#L409'>409</a>
475
+ <a name='L410'></a><a href='#L410'>410</a>
476
+ <a name='L411'></a><a href='#L411'>411</a>
477
+ <a name='L412'></a><a href='#L412'>412</a>
478
+ <a name='L413'></a><a href='#L413'>413</a>
479
+ <a name='L414'></a><a href='#L414'>414</a>
480
+ <a name='L415'></a><a href='#L415'>415</a>
481
+ <a name='L416'></a><a href='#L416'>416</a>
482
+ <a name='L417'></a><a href='#L417'>417</a>
483
+ <a name='L418'></a><a href='#L418'>418</a>
484
+ <a name='L419'></a><a href='#L419'>419</a>
485
+ <a name='L420'></a><a href='#L420'>420</a>
486
+ <a name='L421'></a><a href='#L421'>421</a>
487
+ <a name='L422'></a><a href='#L422'>422</a>
488
+ <a name='L423'></a><a href='#L423'>423</a>
489
+ <a name='L424'></a><a href='#L424'>424</a>
490
+ <a name='L425'></a><a href='#L425'>425</a>
491
+ <a name='L426'></a><a href='#L426'>426</a>
492
+ <a name='L427'></a><a href='#L427'>427</a>
493
+ <a name='L428'></a><a href='#L428'>428</a>
494
+ <a name='L429'></a><a href='#L429'>429</a>
495
+ <a name='L430'></a><a href='#L430'>430</a>
496
+ <a name='L431'></a><a href='#L431'>431</a>
497
+ <a name='L432'></a><a href='#L432'>432</a>
498
+ <a name='L433'></a><a href='#L433'>433</a>
499
+ <a name='L434'></a><a href='#L434'>434</a>
500
+ <a name='L435'></a><a href='#L435'>435</a>
501
+ <a name='L436'></a><a href='#L436'>436</a>
502
+ <a name='L437'></a><a href='#L437'>437</a>
503
+ <a name='L438'></a><a href='#L438'>438</a>
504
+ <a name='L439'></a><a href='#L439'>439</a>
505
+ <a name='L440'></a><a href='#L440'>440</a>
506
+ <a name='L441'></a><a href='#L441'>441</a>
507
+ <a name='L442'></a><a href='#L442'>442</a>
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></td><td class="line-coverage quiet"><span class="cline-any cline-no">&nbsp;</span>
533
+ <span class="cline-any cline-no">&nbsp;</span>
534
+ <span class="cline-any cline-no">&nbsp;</span>
535
+ <span class="cline-any cline-neutral">&nbsp;</span>
536
+ <span class="cline-any cline-neutral">&nbsp;</span>
537
+ <span class="cline-any cline-no">&nbsp;</span>
538
+ <span class="cline-any cline-no">&nbsp;</span>
539
+ <span class="cline-any cline-neutral">&nbsp;</span>
540
+ <span class="cline-any cline-neutral">&nbsp;</span>
541
+ <span class="cline-any cline-no">&nbsp;</span>
542
+ <span class="cline-any cline-no">&nbsp;</span>
543
+ <span class="cline-any cline-no">&nbsp;</span>
544
+ <span class="cline-any cline-neutral">&nbsp;</span>
545
+ <span class="cline-any cline-neutral">&nbsp;</span>
546
+ <span class="cline-any cline-neutral">&nbsp;</span>
547
+ <span class="cline-any cline-no">&nbsp;</span>
548
+ <span class="cline-any cline-no">&nbsp;</span>
549
+ <span class="cline-any cline-neutral">&nbsp;</span>
550
+ <span class="cline-any cline-neutral">&nbsp;</span>
551
+ <span class="cline-any cline-no">&nbsp;</span>
552
+ <span class="cline-any cline-no">&nbsp;</span>
553
+ <span class="cline-any cline-no">&nbsp;</span>
554
+ <span class="cline-any cline-no">&nbsp;</span>
555
+ <span class="cline-any cline-no">&nbsp;</span>
556
+ <span class="cline-any cline-neutral">&nbsp;</span>
557
+ <span class="cline-any cline-neutral">&nbsp;</span>
558
+ <span class="cline-any cline-neutral">&nbsp;</span>
559
+ <span class="cline-any cline-neutral">&nbsp;</span>
560
+ <span class="cline-any cline-neutral">&nbsp;</span>
561
+ <span class="cline-any cline-no">&nbsp;</span>
562
+ <span class="cline-any cline-no">&nbsp;</span>
563
+ <span class="cline-any cline-no">&nbsp;</span>
564
+ <span class="cline-any cline-no">&nbsp;</span>
565
+ <span class="cline-any cline-neutral">&nbsp;</span>
566
+ <span class="cline-any cline-neutral">&nbsp;</span>
567
+ <span class="cline-any cline-neutral">&nbsp;</span>
568
+ <span class="cline-any cline-no">&nbsp;</span>
569
+ <span class="cline-any cline-no">&nbsp;</span>
570
+ <span class="cline-any cline-no">&nbsp;</span>
571
+ <span class="cline-any cline-no">&nbsp;</span>
572
+ <span class="cline-any cline-neutral">&nbsp;</span>
573
+ <span class="cline-any cline-neutral">&nbsp;</span>
574
+ <span class="cline-any cline-no">&nbsp;</span>
575
+ <span class="cline-any cline-no">&nbsp;</span>
576
+ <span class="cline-any cline-neutral">&nbsp;</span>
577
+ <span class="cline-any cline-neutral">&nbsp;</span>
578
+ <span class="cline-any cline-no">&nbsp;</span>
579
+ <span class="cline-any cline-no">&nbsp;</span>
580
+ <span class="cline-any cline-neutral">&nbsp;</span>
581
+ <span class="cline-any cline-no">&nbsp;</span>
582
+ <span class="cline-any cline-neutral">&nbsp;</span>
583
+ <span class="cline-any cline-neutral">&nbsp;</span>
584
+ <span class="cline-any cline-neutral">&nbsp;</span>
585
+ <span class="cline-any cline-neutral">&nbsp;</span>
586
+ <span class="cline-any cline-neutral">&nbsp;</span>
587
+ <span class="cline-any cline-neutral">&nbsp;</span>
588
+ <span class="cline-any cline-neutral">&nbsp;</span>
589
+ <span class="cline-any cline-neutral">&nbsp;</span>
590
+ <span class="cline-any cline-neutral">&nbsp;</span>
591
+ <span class="cline-any cline-neutral">&nbsp;</span>
592
+ <span class="cline-any cline-neutral">&nbsp;</span>
593
+ <span class="cline-any cline-neutral">&nbsp;</span>
594
+ <span class="cline-any cline-neutral">&nbsp;</span>
595
+ <span class="cline-any cline-neutral">&nbsp;</span>
596
+ <span class="cline-any cline-neutral">&nbsp;</span>
597
+ <span class="cline-any cline-neutral">&nbsp;</span>
598
+ <span class="cline-any cline-neutral">&nbsp;</span>
599
+ <span class="cline-any cline-neutral">&nbsp;</span>
600
+ <span class="cline-any cline-neutral">&nbsp;</span>
601
+ <span class="cline-any cline-neutral">&nbsp;</span>
602
+ <span class="cline-any cline-neutral">&nbsp;</span>
603
+ <span class="cline-any cline-neutral">&nbsp;</span>
604
+ <span class="cline-any cline-neutral">&nbsp;</span>
605
+ <span class="cline-any cline-no">&nbsp;</span>
606
+ <span class="cline-any cline-no">&nbsp;</span>
607
+ <span class="cline-any cline-neutral">&nbsp;</span>
608
+ <span class="cline-any cline-no">&nbsp;</span>
609
+ <span class="cline-any cline-neutral">&nbsp;</span>
610
+ <span class="cline-any cline-neutral">&nbsp;</span>
611
+ <span class="cline-any cline-no">&nbsp;</span>
612
+ <span class="cline-any cline-no">&nbsp;</span>
613
+ <span class="cline-any cline-neutral">&nbsp;</span>
614
+ <span class="cline-any cline-neutral">&nbsp;</span>
615
+ <span class="cline-any cline-no">&nbsp;</span>
616
+ <span class="cline-any cline-no">&nbsp;</span>
617
+ <span class="cline-any cline-neutral">&nbsp;</span>
618
+ <span class="cline-any cline-neutral">&nbsp;</span>
619
+ <span class="cline-any cline-neutral">&nbsp;</span>
620
+ <span class="cline-any cline-no">&nbsp;</span>
621
+ <span class="cline-any cline-no">&nbsp;</span>
622
+ <span class="cline-any cline-neutral">&nbsp;</span>
623
+ <span class="cline-any cline-no">&nbsp;</span>
624
+ <span class="cline-any cline-neutral">&nbsp;</span>
625
+ <span class="cline-any cline-neutral">&nbsp;</span>
626
+ <span class="cline-any cline-neutral">&nbsp;</span>
627
+ <span class="cline-any cline-neutral">&nbsp;</span>
628
+ <span class="cline-any cline-neutral">&nbsp;</span>
629
+ <span class="cline-any cline-neutral">&nbsp;</span>
630
+ <span class="cline-any cline-neutral">&nbsp;</span>
631
+ <span class="cline-any cline-no">&nbsp;</span>
632
+ <span class="cline-any cline-no">&nbsp;</span>
633
+ <span class="cline-any cline-no">&nbsp;</span>
634
+ <span class="cline-any cline-neutral">&nbsp;</span>
635
+ <span class="cline-any cline-neutral">&nbsp;</span>
636
+ <span class="cline-any cline-neutral">&nbsp;</span>
637
+ <span class="cline-any cline-neutral">&nbsp;</span>
638
+ <span class="cline-any cline-no">&nbsp;</span>
639
+ <span class="cline-any cline-no">&nbsp;</span>
640
+ <span class="cline-any cline-neutral">&nbsp;</span>
641
+ <span class="cline-any cline-neutral">&nbsp;</span>
642
+ <span class="cline-any cline-no">&nbsp;</span>
643
+ <span class="cline-any cline-neutral">&nbsp;</span>
644
+ <span class="cline-any cline-no">&nbsp;</span>
645
+ <span class="cline-any cline-neutral">&nbsp;</span>
646
+ <span class="cline-any cline-no">&nbsp;</span>
647
+ <span class="cline-any cline-no">&nbsp;</span>
648
+ <span class="cline-any cline-no">&nbsp;</span>
649
+ <span class="cline-any cline-neutral">&nbsp;</span>
650
+ <span class="cline-any cline-neutral">&nbsp;</span>
651
+ <span class="cline-any cline-neutral">&nbsp;</span>
652
+ <span class="cline-any cline-no">&nbsp;</span>
653
+ <span class="cline-any cline-neutral">&nbsp;</span>
654
+ <span class="cline-any cline-neutral">&nbsp;</span>
655
+ <span class="cline-any cline-no">&nbsp;</span>
656
+ <span class="cline-any cline-neutral">&nbsp;</span>
657
+ <span class="cline-any cline-neutral">&nbsp;</span>
658
+ <span class="cline-any cline-no">&nbsp;</span>
659
+ <span class="cline-any cline-no">&nbsp;</span>
660
+ <span class="cline-any cline-neutral">&nbsp;</span>
661
+ <span class="cline-any cline-neutral">&nbsp;</span>
662
+ <span class="cline-any cline-neutral">&nbsp;</span>
663
+ <span class="cline-any cline-no">&nbsp;</span>
664
+ <span class="cline-any cline-no">&nbsp;</span>
665
+ <span class="cline-any cline-neutral">&nbsp;</span>
666
+ <span class="cline-any cline-neutral">&nbsp;</span>
667
+ <span class="cline-any cline-no">&nbsp;</span>
668
+ <span class="cline-any cline-neutral">&nbsp;</span>
669
+ <span class="cline-any cline-no">&nbsp;</span>
670
+ <span class="cline-any cline-neutral">&nbsp;</span>
671
+ <span class="cline-any cline-neutral">&nbsp;</span>
672
+ <span class="cline-any cline-neutral">&nbsp;</span>
673
+ <span class="cline-any cline-neutral">&nbsp;</span>
674
+ <span class="cline-any cline-neutral">&nbsp;</span>
675
+ <span class="cline-any cline-neutral">&nbsp;</span>
676
+ <span class="cline-any cline-no">&nbsp;</span>
677
+ <span class="cline-any cline-neutral">&nbsp;</span>
678
+ <span class="cline-any cline-no">&nbsp;</span>
679
+ <span class="cline-any cline-no">&nbsp;</span>
680
+ <span class="cline-any cline-neutral">&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-neutral">&nbsp;</span>
684
+ <span class="cline-any cline-neutral">&nbsp;</span>
685
+ <span class="cline-any cline-no">&nbsp;</span>
686
+ <span class="cline-any cline-neutral">&nbsp;</span>
687
+ <span class="cline-any cline-neutral">&nbsp;</span>
688
+ <span class="cline-any cline-neutral">&nbsp;</span>
689
+ <span class="cline-any cline-no">&nbsp;</span>
690
+ <span class="cline-any cline-no">&nbsp;</span>
691
+ <span class="cline-any cline-no">&nbsp;</span>
692
+ <span class="cline-any cline-neutral">&nbsp;</span>
693
+ <span class="cline-any cline-no">&nbsp;</span>
694
+ <span class="cline-any cline-neutral">&nbsp;</span>
695
+ <span class="cline-any cline-neutral">&nbsp;</span>
696
+ <span class="cline-any cline-neutral">&nbsp;</span>
697
+ <span class="cline-any cline-neutral">&nbsp;</span>
698
+ <span class="cline-any cline-neutral">&nbsp;</span>
699
+ <span class="cline-any cline-neutral">&nbsp;</span>
700
+ <span class="cline-any cline-no">&nbsp;</span>
701
+ <span class="cline-any cline-no">&nbsp;</span>
702
+ <span class="cline-any cline-neutral">&nbsp;</span>
703
+ <span class="cline-any cline-neutral">&nbsp;</span>
704
+ <span class="cline-any cline-neutral">&nbsp;</span>
705
+ <span class="cline-any cline-neutral">&nbsp;</span>
706
+ <span class="cline-any cline-neutral">&nbsp;</span>
707
+ <span class="cline-any cline-neutral">&nbsp;</span>
708
+ <span class="cline-any cline-neutral">&nbsp;</span>
709
+ <span class="cline-any cline-neutral">&nbsp;</span>
710
+ <span class="cline-any cline-neutral">&nbsp;</span>
711
+ <span class="cline-any cline-neutral">&nbsp;</span>
712
+ <span class="cline-any cline-neutral">&nbsp;</span>
713
+ <span class="cline-any cline-neutral">&nbsp;</span>
714
+ <span class="cline-any cline-neutral">&nbsp;</span>
715
+ <span class="cline-any cline-neutral">&nbsp;</span>
716
+ <span class="cline-any cline-neutral">&nbsp;</span>
717
+ <span class="cline-any cline-neutral">&nbsp;</span>
718
+ <span class="cline-any cline-neutral">&nbsp;</span>
719
+ <span class="cline-any cline-neutral">&nbsp;</span>
720
+ <span class="cline-any cline-neutral">&nbsp;</span>
721
+ <span class="cline-any cline-neutral">&nbsp;</span>
722
+ <span class="cline-any cline-neutral">&nbsp;</span>
723
+ <span class="cline-any cline-neutral">&nbsp;</span>
724
+ <span class="cline-any cline-neutral">&nbsp;</span>
725
+ <span class="cline-any cline-neutral">&nbsp;</span>
726
+ <span class="cline-any cline-neutral">&nbsp;</span>
727
+ <span class="cline-any cline-neutral">&nbsp;</span>
728
+ <span class="cline-any cline-neutral">&nbsp;</span>
729
+ <span class="cline-any cline-neutral">&nbsp;</span>
730
+ <span class="cline-any cline-neutral">&nbsp;</span>
731
+ <span class="cline-any cline-neutral">&nbsp;</span>
732
+ <span class="cline-any cline-neutral">&nbsp;</span>
733
+ <span class="cline-any cline-neutral">&nbsp;</span>
734
+ <span class="cline-any cline-neutral">&nbsp;</span>
735
+ <span class="cline-any cline-no">&nbsp;</span>
736
+ <span class="cline-any cline-neutral">&nbsp;</span>
737
+ <span class="cline-any cline-neutral">&nbsp;</span>
738
+ <span class="cline-any cline-neutral">&nbsp;</span>
739
+ <span class="cline-any cline-neutral">&nbsp;</span>
740
+ <span class="cline-any cline-neutral">&nbsp;</span>
741
+ <span class="cline-any cline-neutral">&nbsp;</span>
742
+ <span class="cline-any cline-neutral">&nbsp;</span>
743
+ <span class="cline-any cline-neutral">&nbsp;</span>
744
+ <span class="cline-any cline-neutral">&nbsp;</span>
745
+ <span class="cline-any cline-neutral">&nbsp;</span>
746
+ <span class="cline-any cline-neutral">&nbsp;</span>
747
+ <span class="cline-any cline-no">&nbsp;</span>
748
+ <span class="cline-any cline-neutral">&nbsp;</span>
749
+ <span class="cline-any cline-neutral">&nbsp;</span>
750
+ <span class="cline-any cline-neutral">&nbsp;</span>
751
+ <span class="cline-any cline-neutral">&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-neutral">&nbsp;</span>
757
+ <span class="cline-any cline-no">&nbsp;</span>
758
+ <span class="cline-any cline-no">&nbsp;</span>
759
+ <span class="cline-any cline-neutral">&nbsp;</span>
760
+ <span class="cline-any cline-neutral">&nbsp;</span>
761
+ <span class="cline-any cline-no">&nbsp;</span>
762
+ <span class="cline-any cline-neutral">&nbsp;</span>
763
+ <span class="cline-any cline-neutral">&nbsp;</span>
764
+ <span class="cline-any cline-neutral">&nbsp;</span>
765
+ <span class="cline-any cline-neutral">&nbsp;</span>
766
+ <span class="cline-any cline-no">&nbsp;</span>
767
+ <span class="cline-any cline-no">&nbsp;</span>
768
+ <span class="cline-any cline-neutral">&nbsp;</span>
769
+ <span class="cline-any cline-neutral">&nbsp;</span>
770
+ <span class="cline-any cline-neutral">&nbsp;</span>
771
+ <span class="cline-any cline-neutral">&nbsp;</span>
772
+ <span class="cline-any cline-no">&nbsp;</span>
773
+ <span class="cline-any cline-no">&nbsp;</span>
774
+ <span class="cline-any cline-no">&nbsp;</span>
775
+ <span class="cline-any cline-neutral">&nbsp;</span>
776
+ <span class="cline-any cline-neutral">&nbsp;</span>
777
+ <span class="cline-any cline-no">&nbsp;</span>
778
+ <span class="cline-any cline-no">&nbsp;</span>
779
+ <span class="cline-any cline-neutral">&nbsp;</span>
780
+ <span class="cline-any cline-no">&nbsp;</span>
781
+ <span class="cline-any cline-no">&nbsp;</span>
782
+ <span class="cline-any cline-neutral">&nbsp;</span>
783
+ <span class="cline-any cline-no">&nbsp;</span>
784
+ <span class="cline-any cline-neutral">&nbsp;</span>
785
+ <span class="cline-any cline-neutral">&nbsp;</span>
786
+ <span class="cline-any cline-neutral">&nbsp;</span>
787
+ <span class="cline-any cline-neutral">&nbsp;</span>
788
+ <span class="cline-any cline-no">&nbsp;</span>
789
+ <span class="cline-any cline-no">&nbsp;</span>
790
+ <span class="cline-any cline-no">&nbsp;</span>
791
+ <span class="cline-any cline-no">&nbsp;</span>
792
+ <span class="cline-any cline-neutral">&nbsp;</span>
793
+ <span class="cline-any cline-neutral">&nbsp;</span>
794
+ <span class="cline-any cline-neutral">&nbsp;</span>
795
+ <span class="cline-any cline-neutral">&nbsp;</span>
796
+ <span class="cline-any cline-no">&nbsp;</span>
797
+ <span class="cline-any cline-no">&nbsp;</span>
798
+ <span class="cline-any cline-no">&nbsp;</span>
799
+ <span class="cline-any cline-no">&nbsp;</span>
800
+ <span class="cline-any cline-neutral">&nbsp;</span>
801
+ <span class="cline-any cline-neutral">&nbsp;</span>
802
+ <span class="cline-any cline-neutral">&nbsp;</span>
803
+ <span class="cline-any cline-neutral">&nbsp;</span>
804
+ <span class="cline-any cline-no">&nbsp;</span>
805
+ <span class="cline-any cline-no">&nbsp;</span>
806
+ <span class="cline-any cline-no">&nbsp;</span>
807
+ <span class="cline-any cline-no">&nbsp;</span>
808
+ <span class="cline-any cline-neutral">&nbsp;</span>
809
+ <span class="cline-any cline-neutral">&nbsp;</span>
810
+ <span class="cline-any cline-neutral">&nbsp;</span>
811
+ <span class="cline-any cline-neutral">&nbsp;</span>
812
+ <span class="cline-any cline-neutral">&nbsp;</span>
813
+ <span class="cline-any cline-no">&nbsp;</span>
814
+ <span class="cline-any cline-no">&nbsp;</span>
815
+ <span class="cline-any cline-no">&nbsp;</span>
816
+ <span class="cline-any cline-neutral">&nbsp;</span>
817
+ <span class="cline-any cline-neutral">&nbsp;</span>
818
+ <span class="cline-any cline-no">&nbsp;</span>
819
+ <span class="cline-any cline-neutral">&nbsp;</span>
820
+ <span class="cline-any cline-no">&nbsp;</span>
821
+ <span class="cline-any cline-neutral">&nbsp;</span>
822
+ <span class="cline-any cline-neutral">&nbsp;</span>
823
+ <span class="cline-any cline-no">&nbsp;</span>
824
+ <span class="cline-any cline-neutral">&nbsp;</span>
825
+ <span class="cline-any cline-neutral">&nbsp;</span>
826
+ <span class="cline-any cline-neutral">&nbsp;</span>
827
+ <span class="cline-any cline-no">&nbsp;</span>
828
+ <span class="cline-any cline-neutral">&nbsp;</span>
829
+ <span class="cline-any cline-neutral">&nbsp;</span>
830
+ <span class="cline-any cline-neutral">&nbsp;</span>
831
+ <span class="cline-any cline-no">&nbsp;</span>
832
+ <span class="cline-any cline-no">&nbsp;</span>
833
+ <span class="cline-any cline-no">&nbsp;</span>
834
+ <span class="cline-any cline-neutral">&nbsp;</span>
835
+ <span class="cline-any cline-no">&nbsp;</span>
836
+ <span class="cline-any cline-no">&nbsp;</span>
837
+ <span class="cline-any cline-no">&nbsp;</span>
838
+ <span class="cline-any cline-no">&nbsp;</span>
839
+ <span class="cline-any cline-neutral">&nbsp;</span>
840
+ <span class="cline-any cline-neutral">&nbsp;</span>
841
+ <span class="cline-any cline-neutral">&nbsp;</span>
842
+ <span class="cline-any cline-no">&nbsp;</span>
843
+ <span class="cline-any cline-neutral">&nbsp;</span>
844
+ <span class="cline-any cline-no">&nbsp;</span>
845
+ <span class="cline-any cline-no">&nbsp;</span>
846
+ <span class="cline-any cline-no">&nbsp;</span>
847
+ <span class="cline-any cline-no">&nbsp;</span>
848
+ <span class="cline-any cline-no">&nbsp;</span>
849
+ <span class="cline-any cline-neutral">&nbsp;</span>
850
+ <span class="cline-any cline-no">&nbsp;</span>
851
+ <span class="cline-any cline-no">&nbsp;</span>
852
+ <span class="cline-any cline-no">&nbsp;</span>
853
+ <span class="cline-any cline-no">&nbsp;</span>
854
+ <span class="cline-any cline-no">&nbsp;</span>
855
+ <span class="cline-any cline-neutral">&nbsp;</span>
856
+ <span class="cline-any cline-no">&nbsp;</span>
857
+ <span class="cline-any cline-no">&nbsp;</span>
858
+ <span class="cline-any cline-no">&nbsp;</span>
859
+ <span class="cline-any cline-no">&nbsp;</span>
860
+ <span class="cline-any cline-no">&nbsp;</span>
861
+ <span class="cline-any cline-neutral">&nbsp;</span>
862
+ <span class="cline-any cline-no">&nbsp;</span>
863
+ <span class="cline-any cline-neutral">&nbsp;</span>
864
+ <span class="cline-any cline-neutral">&nbsp;</span>
865
+ <span class="cline-any cline-no">&nbsp;</span>
866
+ <span class="cline-any cline-neutral">&nbsp;</span>
867
+ <span class="cline-any cline-neutral">&nbsp;</span>
868
+ <span class="cline-any cline-no">&nbsp;</span>
869
+ <span class="cline-any cline-neutral">&nbsp;</span>
870
+ <span class="cline-any cline-no">&nbsp;</span>
871
+ <span class="cline-any cline-no">&nbsp;</span>
872
+ <span class="cline-any cline-neutral">&nbsp;</span>
873
+ <span class="cline-any cline-neutral">&nbsp;</span>
874
+ <span class="cline-any cline-neutral">&nbsp;</span>
875
+ <span class="cline-any cline-no">&nbsp;</span>
876
+ <span class="cline-any cline-no">&nbsp;</span>
877
+ <span class="cline-any cline-neutral">&nbsp;</span>
878
+ <span class="cline-any cline-neutral">&nbsp;</span>
879
+ <span class="cline-any cline-neutral">&nbsp;</span>
880
+ <span class="cline-any cline-no">&nbsp;</span>
881
+ <span class="cline-any cline-no">&nbsp;</span>
882
+ <span class="cline-any cline-no">&nbsp;</span>
883
+ <span class="cline-any cline-neutral">&nbsp;</span>
884
+ <span class="cline-any cline-no">&nbsp;</span>
885
+ <span class="cline-any cline-no">&nbsp;</span>
886
+ <span class="cline-any cline-no">&nbsp;</span>
887
+ <span class="cline-any cline-neutral">&nbsp;</span>
888
+ <span class="cline-any cline-no">&nbsp;</span>
889
+ <span class="cline-any cline-no">&nbsp;</span>
890
+ <span class="cline-any cline-neutral">&nbsp;</span>
891
+ <span class="cline-any cline-neutral">&nbsp;</span>
892
+ <span class="cline-any cline-neutral">&nbsp;</span>
893
+ <span class="cline-any cline-neutral">&nbsp;</span>
894
+ <span class="cline-any cline-neutral">&nbsp;</span>
895
+ <span class="cline-any cline-neutral">&nbsp;</span>
896
+ <span class="cline-any cline-neutral">&nbsp;</span>
897
+ <span class="cline-any cline-neutral">&nbsp;</span>
898
+ <span class="cline-any cline-neutral">&nbsp;</span>
899
+ <span class="cline-any cline-no">&nbsp;</span>
900
+ <span class="cline-any cline-no">&nbsp;</span>
901
+ <span class="cline-any cline-no">&nbsp;</span>
902
+ <span class="cline-any cline-no">&nbsp;</span>
903
+ <span class="cline-any cline-neutral">&nbsp;</span>
904
+ <span class="cline-any cline-no">&nbsp;</span>
905
+ <span class="cline-any cline-no">&nbsp;</span>
906
+ <span class="cline-any cline-neutral">&nbsp;</span>
907
+ <span class="cline-any cline-neutral">&nbsp;</span>
908
+ <span class="cline-any cline-neutral">&nbsp;</span>
909
+ <span class="cline-any cline-no">&nbsp;</span>
910
+ <span class="cline-any cline-no">&nbsp;</span>
911
+ <span class="cline-any cline-no">&nbsp;</span>
912
+ <span class="cline-any cline-no">&nbsp;</span>
913
+ <span class="cline-any cline-no">&nbsp;</span>
914
+ <span class="cline-any cline-neutral">&nbsp;</span>
915
+ <span class="cline-any cline-no">&nbsp;</span>
916
+ <span class="cline-any cline-neutral">&nbsp;</span>
917
+ <span class="cline-any cline-no">&nbsp;</span>
918
+ <span class="cline-any cline-no">&nbsp;</span>
919
+ <span class="cline-any cline-neutral">&nbsp;</span>
920
+ <span class="cline-any cline-neutral">&nbsp;</span>
921
+ <span class="cline-any cline-neutral">&nbsp;</span>
922
+ <span class="cline-any cline-neutral">&nbsp;</span>
923
+ <span class="cline-any cline-no">&nbsp;</span>
924
+ <span class="cline-any cline-neutral">&nbsp;</span>
925
+ <span class="cline-any cline-neutral">&nbsp;</span>
926
+ <span class="cline-any cline-no">&nbsp;</span>
927
+ <span class="cline-any cline-no">&nbsp;</span>
928
+ <span class="cline-any cline-no">&nbsp;</span>
929
+ <span class="cline-any cline-neutral">&nbsp;</span>
930
+ <span class="cline-any cline-no">&nbsp;</span>
931
+ <span class="cline-any cline-no">&nbsp;</span>
932
+ <span class="cline-any cline-no">&nbsp;</span>
933
+ <span class="cline-any cline-neutral">&nbsp;</span>
934
+ <span class="cline-any cline-neutral">&nbsp;</span>
935
+ <span class="cline-any cline-no">&nbsp;</span>
936
+ <span class="cline-any cline-no">&nbsp;</span>
937
+ <span class="cline-any cline-no">&nbsp;</span>
938
+ <span class="cline-any cline-no">&nbsp;</span>
939
+ <span class="cline-any cline-no">&nbsp;</span>
940
+ <span class="cline-any cline-no">&nbsp;</span>
941
+ <span class="cline-any cline-neutral">&nbsp;</span>
942
+ <span class="cline-any cline-no">&nbsp;</span>
943
+ <span class="cline-any cline-no">&nbsp;</span>
944
+ <span class="cline-any cline-neutral">&nbsp;</span>
945
+ <span class="cline-any cline-neutral">&nbsp;</span>
946
+ <span class="cline-any cline-neutral">&nbsp;</span>
947
+ <span class="cline-any cline-neutral">&nbsp;</span>
948
+ <span class="cline-any cline-no">&nbsp;</span>
949
+ <span class="cline-any cline-no">&nbsp;</span>
950
+ <span class="cline-any cline-neutral">&nbsp;</span>
951
+ <span class="cline-any cline-no">&nbsp;</span>
952
+ <span class="cline-any cline-no">&nbsp;</span>
953
+ <span class="cline-any cline-neutral">&nbsp;</span>
954
+ <span class="cline-any cline-no">&nbsp;</span>
955
+ <span class="cline-any cline-no">&nbsp;</span>
956
+ <span class="cline-any cline-neutral">&nbsp;</span>
957
+ <span class="cline-any cline-no">&nbsp;</span>
958
+ <span class="cline-any cline-no">&nbsp;</span>
959
+ <span class="cline-any cline-neutral">&nbsp;</span>
960
+ <span class="cline-any cline-neutral">&nbsp;</span>
961
+ <span class="cline-any cline-neutral">&nbsp;</span>
962
+ <span class="cline-any cline-neutral">&nbsp;</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-neutral">&nbsp;</span>
967
+ <span class="cline-any cline-neutral">&nbsp;</span>
968
+ <span class="cline-any cline-no">&nbsp;</span>
969
+ <span class="cline-any cline-no">&nbsp;</span>
970
+ <span class="cline-any cline-neutral">&nbsp;</span>
971
+ <span class="cline-any cline-neutral">&nbsp;</span>
972
+ <span class="cline-any cline-no">&nbsp;</span>
973
+ <span class="cline-any cline-neutral">&nbsp;</span>
974
+ <span class="cline-any cline-neutral">&nbsp;</span>
975
+ <span class="cline-any cline-neutral">&nbsp;</span>
976
+ <span class="cline-any cline-neutral">&nbsp;</span>
977
+ <span class="cline-any cline-neutral">&nbsp;</span>
978
+ <span class="cline-any cline-neutral">&nbsp;</span>
979
+ <span class="cline-any cline-neutral">&nbsp;</span>
980
+ <span class="cline-any cline-neutral">&nbsp;</span>
981
+ <span class="cline-any cline-no">&nbsp;</span>
982
+ <span class="cline-any cline-no">&nbsp;</span>
983
+ <span class="cline-any cline-neutral">&nbsp;</span>
984
+ <span class="cline-any cline-neutral">&nbsp;</span>
985
+ <span class="cline-any cline-no">&nbsp;</span>
986
+ <span class="cline-any cline-no">&nbsp;</span>
987
+ <span class="cline-any cline-neutral">&nbsp;</span>
988
+ <span class="cline-any cline-neutral">&nbsp;</span>
989
+ <span class="cline-any cline-neutral">&nbsp;</span>
990
+ <span class="cline-any cline-no">&nbsp;</span>
991
+ <span class="cline-any cline-no">&nbsp;</span>
992
+ <span class="cline-any cline-no">&nbsp;</span>
993
+ <span class="cline-any cline-neutral">&nbsp;</span>
994
+ <span class="cline-any cline-no">&nbsp;</span>
995
+ <span class="cline-any cline-no">&nbsp;</span>
996
+ <span class="cline-any cline-neutral">&nbsp;</span>
997
+ <span class="cline-any cline-neutral">&nbsp;</span>
998
+ <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">const { app, BrowserWindow, globalShortcut, dialog, ipcMain, screen, Tray, Menu, nativeImage, shell } = <span class="cstat-no" title="statement not covered" >require('electron');</span>
999
+ const path = <span class="cstat-no" title="statement not covered" >require('path');</span>
1000
+ const fs = <span class="cstat-no" title="statement not covered" >require('fs');</span>
1001
+ &nbsp;
1002
+ // Data storage path
1003
+ const userDataPath = <span class="cstat-no" title="statement not covered" >app.getPath('userData');</span>
1004
+ const dataFilePath = <span class="cstat-no" title="statement not covered" >path.join(userDataPath, 'floatnote-data.json');</span>
1005
+ &nbsp;
1006
+ // Ensure only one instance of the app runs
1007
+ const gotTheLock = <span class="cstat-no" title="statement not covered" >app.requestSingleInstanceLock();</span>
1008
+ <span class="cstat-no" title="statement not covered" >if (!gotTheLock) {</span>
1009
+ <span class="cstat-no" title="statement not covered" > app.quit();</span>
1010
+ }
1011
+ &nbsp;
1012
+ // Single window reference
1013
+ let mainWindow = <span class="cstat-no" title="statement not covered" >null;</span>
1014
+ let tray = <span class="cstat-no" title="statement not covered" >null;</span>
1015
+ &nbsp;
1016
+ // Handle second instance attempt - show existing window
1017
+ <span class="cstat-no" title="statement not covered" >app.on('second-instance', <span class="fstat-no" title="function not covered" >()</span> =&gt; {</span>
1018
+ <span class="cstat-no" title="statement not covered" > if (mainWindow) {</span>
1019
+ <span class="cstat-no" title="statement not covered" > if (mainWindow.isMinimized()) <span class="cstat-no" title="statement not covered" >mainWindow.restore();</span></span>
1020
+ <span class="cstat-no" title="statement not covered" > mainWindow.show();</span>
1021
+ <span class="cstat-no" title="statement not covered" > mainWindow.focus();</span>
1022
+ }
1023
+ });
1024
+ &nbsp;
1025
+ function <span class="fstat-no" title="function not covered" >createWindow(</span>options = <span class="branch-0 cbranch-no" title="branch not covered" >{})</span> {
1026
+ // If window already exists, just show it
1027
+ <span class="cstat-no" title="statement not covered" > if (mainWindow &amp;&amp; !mainWindow.isDestroyed()) {</span>
1028
+ <span class="cstat-no" title="statement not covered" > mainWindow.show();</span>
1029
+ <span class="cstat-no" title="statement not covered" > mainWindow.focus();</span>
1030
+ <span class="cstat-no" title="statement not covered" > return mainWindow;</span>
1031
+ }
1032
+ &nbsp;
1033
+ // Get the display where the cursor is (or primary display)
1034
+ const cursorPoint = <span class="cstat-no" title="statement not covered" >screen.getCursorScreenPoint();</span>
1035
+ const currentDisplay = <span class="cstat-no" title="statement not covered" >screen.getDisplayNearestPoint(cursorPoint);</span>
1036
+ const { width: screenWidth, height: screenHeight } = <span class="cstat-no" title="statement not covered" >currentDisplay.workAreaSize;</span>
1037
+ const { x: displayX, y: displayY } = <span class="cstat-no" title="statement not covered" >currentDisplay.workArea;</span>
1038
+ &nbsp;
1039
+ // Default: 30% width, full height, anchored to right
1040
+ const windowWidth = <span class="cstat-no" title="statement not covered" >Math.round(screenWidth * 0.3);</span>
1041
+ const windowHeight = <span class="cstat-no" title="statement not covered" >screenHeight;</span>
1042
+ &nbsp;
1043
+ // Position on the right edge of the current display
1044
+ const x = <span class="cstat-no" title="statement not covered" >options.x ?? (displayX + screenWidth - windowWidth);</span>
1045
+ const y = <span class="cstat-no" title="statement not covered" >options.y ?? displayY;</span>
1046
+ &nbsp;
1047
+ const win = <span class="cstat-no" title="statement not covered" >new BrowserWindow({</span>
1048
+ width: windowWidth,
1049
+ height: windowHeight,
1050
+ x: x,
1051
+ y: y,
1052
+ transparent: true,
1053
+ backgroundColor: '#00000000',
1054
+ frame: false,
1055
+ alwaysOnTop: true,
1056
+ hasShadow: false,
1057
+ resizable: true,
1058
+ movable: true,
1059
+ skipTaskbar: false,
1060
+ // macOS vibrancy settings for blur effect
1061
+ vibrancy: null, // Start with no vibrancy, set dynamically
1062
+ visualEffectState: 'active',
1063
+ webPreferences: {
1064
+ nodeIntegration: false,
1065
+ contextIsolation: true,
1066
+ preload: path.join(__dirname, 'preload.js')
1067
+ }
1068
+ });
1069
+ &nbsp;
1070
+ // Ensure window stays on top at all times
1071
+ <span class="cstat-no" title="statement not covered" > win.setAlwaysOnTop(true, 'floating', 1);</span>
1072
+ <span class="cstat-no" title="statement not covered" > win.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true });</span>
1073
+ &nbsp;
1074
+ <span class="cstat-no" title="statement not covered" > win.loadFile(path.join(__dirname, 'index.html'));</span>
1075
+ &nbsp;
1076
+ // Track focus for yellow glow effect
1077
+ <span class="cstat-no" title="statement not covered" > win.on('focus', <span class="fstat-no" title="function not covered" >()</span> =&gt; {</span>
1078
+ <span class="cstat-no" title="statement not covered" > win.webContents.send('window-focus', true);</span>
1079
+ });
1080
+ &nbsp;
1081
+ <span class="cstat-no" title="statement not covered" > win.on('blur', <span class="fstat-no" title="function not covered" >()</span> =&gt; {</span>
1082
+ <span class="cstat-no" title="statement not covered" > win.webContents.send('window-focus', false);</span>
1083
+ });
1084
+ &nbsp;
1085
+ // Handle close confirmation
1086
+ <span class="cstat-no" title="statement not covered" > win.on('close', <span class="fstat-no" title="function not covered" >(e</span>) =&gt; {</span>
1087
+ <span class="cstat-no" title="statement not covered" > e.preventDefault();</span>
1088
+ &nbsp;
1089
+ <span class="cstat-no" title="statement not covered" > dialog.showMessageBox(win, {</span>
1090
+ type: 'warning',
1091
+ buttons: ['Close', 'Cancel'],
1092
+ defaultId: 1,
1093
+ title: 'Close Floatnote?',
1094
+ message: 'Are you sure you want to close Floatnote?',
1095
+ detail: 'Any unsaved content will be lost.'
1096
+ }).then(<span class="fstat-no" title="function not covered" >re</span>sult =&gt; {
1097
+ <span class="cstat-no" title="statement not covered" > if (result.response === 0) {</span>
1098
+ <span class="cstat-no" title="statement not covered" > mainWindow = null;</span>
1099
+ <span class="cstat-no" title="statement not covered" > win.destroy();</span>
1100
+ }
1101
+ });
1102
+ });
1103
+ &nbsp;
1104
+ <span class="cstat-no" title="statement not covered" > mainWindow = win;</span>
1105
+ <span class="cstat-no" title="statement not covered" > return win;</span>
1106
+ }
1107
+ &nbsp;
1108
+ <span class="cstat-no" title="statement not covered" >app.whenReady().then(<span class="fstat-no" title="function not covered" >()</span> =&gt; {</span>
1109
+ // Set dock icon for macOS app switcher
1110
+ <span class="cstat-no" title="statement not covered" > if (process.platform === 'darwin' &amp;&amp; app.dock) {</span>
1111
+ // Create a 512x512 dock icon (simple "G" icon)
1112
+ const dockIconBase64 = <span class="cstat-no" title="statement not covered" >'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';</span>
1113
+ const dockIcon = <span class="cstat-no" title="statement not covered" >nativeImage.createFromDataURL(`data:image/png;base64,${dockIconBase64}`);</span>
1114
+ <span class="cstat-no" title="statement not covered" > app.dock.setIcon(dockIcon);</span>
1115
+ }
1116
+ &nbsp;
1117
+ // Create menu bar tray icon
1118
+ <span class="cstat-no" title="statement not covered" > createTray();</span>
1119
+ &nbsp;
1120
+ // Create the window
1121
+ <span class="cstat-no" title="statement not covered" > createWindow();</span>
1122
+ &nbsp;
1123
+ // Register global shortcut to toggle Floatnote (Cmd+Shift+G)
1124
+ <span class="cstat-no" title="statement not covered" > globalShortcut.register('CommandOrControl+Shift+G', <span class="fstat-no" title="function not covered" >()</span> =&gt; {</span>
1125
+ <span class="cstat-no" title="statement not covered" > toggleFloatnote();</span>
1126
+ });
1127
+ &nbsp;
1128
+ // Alternative quick toggle: Option+Space (like Spotlight)
1129
+ <span class="cstat-no" title="statement not covered" > globalShortcut.register('Alt+Space', <span class="fstat-no" title="function not covered" >()</span> =&gt; {</span>
1130
+ <span class="cstat-no" title="statement not covered" > toggleFloatnote();</span>
1131
+ });
1132
+ &nbsp;
1133
+ <span class="cstat-no" title="statement not covered" > app.on('activate', <span class="fstat-no" title="function not covered" >()</span> =&gt; {</span>
1134
+ // Show existing window or create new one
1135
+ <span class="cstat-no" title="statement not covered" > createWindow();</span>
1136
+ });
1137
+ });
1138
+ &nbsp;
1139
+ function <span class="fstat-no" title="function not covered" >createTray(</span>) {
1140
+ // Create a 16x16 template icon embedded as base64
1141
+ // This is a simple "G" letter icon that works as a macOS template image
1142
+ const iconBase64 = <span class="cstat-no" title="statement not covered" >'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAhGVYSWZNTQAqAAAACAAFARIAAwAAAAEAAQAAARoABQAAAAEAAABKARsABQAAAAEAAABSASgAAwAAAAEAAgAAh2kABAAAAAEAAABaAAAAAAAAAEgAAAABAAAASAAAAAEAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAEKADAAQAAAABAAAAEAAAAABBPTzcAAAACXBIWXMAAAsTAAALEwEAmpwYAAACamlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNi4wLjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyIKICAgICAgICAgICAgeG1sbnM6ZXhpZj0iaHR0cDovL25zLmFkb2JlLmNvbS9leGlmLzEuMC8iPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICAgICA8ZXhpZjpQaXhlbFhEaW1lbnNpb24+MTY8L2V4aWY6UGl4ZWxYRGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpQaXhlbFlEaW1lbnNpb24+MTY8L2V4aWY6UGl4ZWxZRGltZW5zaW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KXwjvyAAAALNJREFUOBFjZGBg+M+ABjCYGP4z/GdgUGBkYDjPwMDwH0XOf4b/TP8ZGM4zMjD8h8oBOU9AgMxMBrDAf4b/jAz/kZ3AwPD/PyMDw38kJwAF/zOC+CCJf0BBRkYGhv8MDIwMDAwgJ/xnAgr8Z2D4z8Dw//9/BkZGRob/ICdAxRj+MzAygBQCJRgYGP6D+EB5kPP/MzD8R3ECUAwiBhYEOYGRkeE/0GAGBgYgG+oloCAA7jIp5c7VUCUAAAAASUVORK5CYII=';</span>
1143
+ &nbsp;
1144
+ const icon = <span class="cstat-no" title="statement not covered" >nativeImage.createFromDataURL(`data:image/png;base64,${iconBase64}`);</span>
1145
+ <span class="cstat-no" title="statement not covered" > icon.setTemplateImage(true);</span>
1146
+ &nbsp;
1147
+ <span class="cstat-no" title="statement not covered" > tray = new Tray(icon);</span>
1148
+ <span class="cstat-no" title="statement not covered" > tray.setToolTip('Floatnote');</span>
1149
+ &nbsp;
1150
+ // Create context menu for right-click
1151
+ const contextMenu = <span class="cstat-no" title="statement not covered" >Menu.buildFromTemplate([</span>
1152
+ {
1153
+ label: 'Show Floatnote',
1154
+ click: <span class="fstat-no" title="function not covered" >()</span> =&gt; {
1155
+ <span class="cstat-no" title="statement not covered" > if (mainWindow &amp;&amp; !mainWindow.isDestroyed()) {</span>
1156
+ <span class="cstat-no" title="statement not covered" > mainWindow.show();</span>
1157
+ <span class="cstat-no" title="statement not covered" > mainWindow.focus();</span>
1158
+ } else {
1159
+ <span class="cstat-no" title="statement not covered" > createWindow();</span>
1160
+ }
1161
+ }
1162
+ },
1163
+ {
1164
+ label: 'Hide Floatnote',
1165
+ click: <span class="fstat-no" title="function not covered" >()</span> =&gt; {
1166
+ <span class="cstat-no" title="statement not covered" > if (mainWindow &amp;&amp; !mainWindow.isDestroyed()) {</span>
1167
+ <span class="cstat-no" title="statement not covered" > mainWindow.hide();</span>
1168
+ }
1169
+ }
1170
+ },
1171
+ { type: 'separator' },
1172
+ {
1173
+ label: 'Shortcuts',
1174
+ submenu: [
1175
+ { label: 'Toggle: ⌘⇧G', enabled: false },
1176
+ { label: 'Quick Toggle: ⌥Space', enabled: false },
1177
+ { label: 'Quick Toggle: ⌃`', enabled: false },
1178
+ { label: 'Settings: ⌘,', enabled: false },
1179
+ { label: 'Close: ⌘W', enabled: false },
1180
+ { type: 'separator' },
1181
+ { label: 'Undo: ⌘Z', enabled: false },
1182
+ { label: 'Redo: ⌘⇧Z', enabled: false },
1183
+ { type: 'separator' },
1184
+ { label: 'Select Mode: V', enabled: false },
1185
+ { label: 'Draw Mode: B', enabled: false },
1186
+ { label: 'Text Mode: T', enabled: false },
1187
+ { type: 'separator' },
1188
+ { label: 'Copy: ⌘C', enabled: false },
1189
+ { label: 'Paste: ⌘V', enabled: false },
1190
+ { label: 'Delete: D', enabled: false },
1191
+ { type: 'separator' },
1192
+ { label: 'Zoom In: ⌘+', enabled: false },
1193
+ { label: 'Zoom Out: ⌘-', enabled: false },
1194
+ { label: 'Reset Zoom: ⌘0', enabled: false }
1195
+ ]
1196
+ },
1197
+ { type: 'separator' },
1198
+ {
1199
+ label: 'About Floatnote',
1200
+ click: <span class="fstat-no" title="function not covered" >()</span> =&gt; {
1201
+ <span class="cstat-no" title="statement not covered" > dialog.showMessageBox({</span>
1202
+ type: 'info',
1203
+ title: 'About Floatnote',
1204
+ message: 'Floatnote',
1205
+ detail: 'A transparent drawing and note-taking overlay for macOS.\n\nVersion 1.0.0'
1206
+ });
1207
+ }
1208
+ },
1209
+ { type: 'separator' },
1210
+ {
1211
+ label: 'Quit Floatnote',
1212
+ accelerator: 'CommandOrControl+Q',
1213
+ click: <span class="fstat-no" title="function not covered" >()</span> =&gt; <span class="cstat-no" title="statement not covered" >app.quit()</span>
1214
+ }
1215
+ ]);
1216
+ &nbsp;
1217
+ // Left-click: Show/focus the window
1218
+ <span class="cstat-no" title="statement not covered" > tray.on('click', <span class="fstat-no" title="function not covered" >()</span> =&gt; {</span>
1219
+ <span class="cstat-no" title="statement not covered" > if (mainWindow &amp;&amp; !mainWindow.isDestroyed()) {</span>
1220
+ <span class="cstat-no" title="statement not covered" > if (mainWindow.isVisible()) {</span>
1221
+ <span class="cstat-no" title="statement not covered" > mainWindow.focus();</span>
1222
+ } else {
1223
+ <span class="cstat-no" title="statement not covered" > mainWindow.show();</span>
1224
+ <span class="cstat-no" title="statement not covered" > mainWindow.focus();</span>
1225
+ }
1226
+ } else {
1227
+ <span class="cstat-no" title="statement not covered" > createWindow();</span>
1228
+ }
1229
+ });
1230
+ &nbsp;
1231
+ // Right-click: Show context menu
1232
+ <span class="cstat-no" title="statement not covered" > tray.on('right-click', <span class="fstat-no" title="function not covered" >()</span> =&gt; {</span>
1233
+ <span class="cstat-no" title="statement not covered" > tray.popUpContextMenu(contextMenu);</span>
1234
+ });
1235
+ }
1236
+ &nbsp;
1237
+ function <span class="fstat-no" title="function not covered" >toggleFloatnote(</span>) {
1238
+ <span class="cstat-no" title="statement not covered" > if (!mainWindow || mainWindow.isDestroyed()) {</span>
1239
+ <span class="cstat-no" title="statement not covered" > createWindow();</span>
1240
+ <span class="cstat-no" title="statement not covered" > return;</span>
1241
+ }
1242
+ &nbsp;
1243
+ <span class="cstat-no" title="statement not covered" > if (mainWindow.isVisible()) {</span>
1244
+ <span class="cstat-no" title="statement not covered" > mainWindow.hide();</span>
1245
+ } else {
1246
+ <span class="cstat-no" title="statement not covered" > mainWindow.show();</span>
1247
+ <span class="cstat-no" title="statement not covered" > mainWindow.focus();</span>
1248
+ // Notify renderer that window was shown via toggle
1249
+ <span class="cstat-no" title="statement not covered" > mainWindow.webContents.send('window-toggled-open');</span>
1250
+ }
1251
+ }
1252
+ &nbsp;
1253
+ // Handle Cmd+W from renderer
1254
+ <span class="cstat-no" title="statement not covered" >ipcMain.on('close-window', <span class="fstat-no" title="function not covered" >(e</span>vent) =&gt; {</span>
1255
+ const win = <span class="cstat-no" title="statement not covered" >BrowserWindow.fromWebContents(event.sender);</span>
1256
+ <span class="cstat-no" title="statement not covered" > if (win) {</span>
1257
+ <span class="cstat-no" title="statement not covered" > win.close();</span>
1258
+ }
1259
+ });
1260
+ &nbsp;
1261
+ // Handle hide window (no confirmation, just hide)
1262
+ <span class="cstat-no" title="statement not covered" >ipcMain.on('hide-window', <span class="fstat-no" title="function not covered" >(e</span>vent) =&gt; {</span>
1263
+ const win = <span class="cstat-no" title="statement not covered" >BrowserWindow.fromWebContents(event.sender);</span>
1264
+ <span class="cstat-no" title="statement not covered" > if (win) {</span>
1265
+ <span class="cstat-no" title="statement not covered" > win.hide();</span>
1266
+ }
1267
+ });
1268
+ &nbsp;
1269
+ // Handle pin toggle from renderer
1270
+ <span class="cstat-no" title="statement not covered" >ipcMain.on('set-pinned', <span class="fstat-no" title="function not covered" >(e</span>vent, pinned) =&gt; {</span>
1271
+ const win = <span class="cstat-no" title="statement not covered" >BrowserWindow.fromWebContents(event.sender);</span>
1272
+ <span class="cstat-no" title="statement not covered" > if (win) {</span>
1273
+ <span class="cstat-no" title="statement not covered" > win.setAlwaysOnTop(pinned, 'floating', 1);</span>
1274
+ }
1275
+ });
1276
+ &nbsp;
1277
+ // Handle background mode change from renderer
1278
+ // Uses macOS native vibrancy for blur effect
1279
+ <span class="cstat-no" title="statement not covered" >ipcMain.on('set-background-mode', <span class="fstat-no" title="function not covered" >(e</span>vent, mode) =&gt; {</span>
1280
+ const win = <span class="cstat-no" title="statement not covered" >BrowserWindow.fromWebContents(event.sender);</span>
1281
+ <span class="cstat-no" title="statement not covered" > if (!win) <span class="cstat-no" title="statement not covered" >return;</span></span>
1282
+ &nbsp;
1283
+ // Set vibrancy based on mode
1284
+ <span class="cstat-no" title="statement not covered" > if (mode === 'blur') {</span>
1285
+ // Use macOS native vibrancy for blur effect
1286
+ <span class="cstat-no" title="statement not covered" > win.setVibrancy('under-window');</span>
1287
+ } else {
1288
+ // Remove vibrancy for transparent or dark modes
1289
+ <span class="cstat-no" title="statement not covered" > win.setVibrancy(null);</span>
1290
+ }
1291
+ &nbsp;
1292
+ // Notify renderer of the mode change
1293
+ <span class="cstat-no" title="statement not covered" > win.webContents.send('background-mode-changed', mode);</span>
1294
+ });
1295
+ &nbsp;
1296
+ // Handle window size change from renderer
1297
+ <span class="cstat-no" title="statement not covered" >ipcMain.on('set-window-size', <span class="fstat-no" title="function not covered" >(e</span>vent, size) =&gt; {</span>
1298
+ const win = <span class="cstat-no" title="statement not covered" >BrowserWindow.fromWebContents(event.sender);</span>
1299
+ <span class="cstat-no" title="statement not covered" > if (!win) <span class="cstat-no" title="statement not covered" >return;</span></span>
1300
+ &nbsp;
1301
+ const cursorPoint = <span class="cstat-no" title="statement not covered" >screen.getCursorScreenPoint();</span>
1302
+ const currentDisplay = <span class="cstat-no" title="statement not covered" >screen.getDisplayNearestPoint(cursorPoint);</span>
1303
+ const { width: screenWidth, height: screenHeight } = <span class="cstat-no" title="statement not covered" >currentDisplay.workAreaSize;</span>
1304
+ const { x: displayX, y: displayY } = <span class="cstat-no" title="statement not covered" >currentDisplay.workArea;</span>
1305
+ &nbsp;
1306
+ let newWidth, newHeight, newX, newY;
1307
+ &nbsp;
1308
+ <span class="cstat-no" title="statement not covered" > switch (size) {</span>
1309
+ case 'sm':
1310
+ <span class="cstat-no" title="statement not covered" > newWidth = Math.round(screenWidth * 0.33);</span>
1311
+ <span class="cstat-no" title="statement not covered" > newHeight = Math.round(screenHeight * 0.5);</span>
1312
+ <span class="cstat-no" title="statement not covered" > newX = displayX + screenWidth - newWidth;</span>
1313
+ <span class="cstat-no" title="statement not covered" > newY = displayY + screenHeight - newHeight;</span>
1314
+ <span class="cstat-no" title="statement not covered" > break;</span>
1315
+ case 'md':
1316
+ <span class="cstat-no" title="statement not covered" > newWidth = Math.round(screenWidth * 0.33);</span>
1317
+ <span class="cstat-no" title="statement not covered" > newHeight = screenHeight;</span>
1318
+ <span class="cstat-no" title="statement not covered" > newX = displayX + screenWidth - newWidth;</span>
1319
+ <span class="cstat-no" title="statement not covered" > newY = displayY;</span>
1320
+ <span class="cstat-no" title="statement not covered" > break;</span>
1321
+ case 'lg':
1322
+ <span class="cstat-no" title="statement not covered" > newWidth = screenWidth;</span>
1323
+ <span class="cstat-no" title="statement not covered" > newHeight = screenHeight;</span>
1324
+ <span class="cstat-no" title="statement not covered" > newX = displayX;</span>
1325
+ <span class="cstat-no" title="statement not covered" > newY = displayY;</span>
1326
+ <span class="cstat-no" title="statement not covered" > break;</span>
1327
+ default:
1328
+ <span class="cstat-no" title="statement not covered" > return;</span>
1329
+ }
1330
+ &nbsp;
1331
+ <span class="cstat-no" title="statement not covered" > win.setBounds({ x: newX, y: newY, width: newWidth, height: newHeight });</span>
1332
+ });
1333
+ &nbsp;
1334
+ <span class="cstat-no" title="statement not covered" >app.on('window-all-closed', <span class="fstat-no" title="function not covered" >()</span> =&gt; {</span>
1335
+ // Don't quit on macOS
1336
+ <span class="cstat-no" title="statement not covered" > if (process.platform !== 'darwin') {</span>
1337
+ <span class="cstat-no" title="statement not covered" > app.quit();</span>
1338
+ }
1339
+ });
1340
+ &nbsp;
1341
+ <span class="cstat-no" title="statement not covered" >app.on('will-quit', <span class="fstat-no" title="function not covered" >()</span> =&gt; {</span>
1342
+ <span class="cstat-no" title="statement not covered" > globalShortcut.unregisterAll();</span>
1343
+ });
1344
+ &nbsp;
1345
+ // Handle horizontal resize from left edge
1346
+ <span class="cstat-no" title="statement not covered" >ipcMain.on('resize-window-left', <span class="fstat-no" title="function not covered" >(e</span>vent, deltaX) =&gt; {</span>
1347
+ const win = <span class="cstat-no" title="statement not covered" >BrowserWindow.fromWebContents(event.sender);</span>
1348
+ <span class="cstat-no" title="statement not covered" > if (!win) <span class="cstat-no" title="statement not covered" >return;</span></span>
1349
+ &nbsp;
1350
+ const bounds = <span class="cstat-no" title="statement not covered" >win.getBounds();</span>
1351
+ const minWidth = <span class="cstat-no" title="statement not covered" >200;</span>
1352
+ const newWidth = <span class="cstat-no" title="statement not covered" >bounds.width - deltaX;</span>
1353
+ &nbsp;
1354
+ <span class="cstat-no" title="statement not covered" > if (newWidth &gt;= minWidth) {</span>
1355
+ <span class="cstat-no" title="statement not covered" > win.setBounds({</span>
1356
+ x: bounds.x + deltaX,
1357
+ y: bounds.y,
1358
+ width: newWidth,
1359
+ height: bounds.height
1360
+ });
1361
+ }
1362
+ });
1363
+ &nbsp;
1364
+ // Data persistence handlers
1365
+ <span class="cstat-no" title="statement not covered" >ipcMain.handle('save-data', <span class="fstat-no" title="function not covered" >as</span>ync (event, data) =&gt; {</span>
1366
+ <span class="cstat-no" title="statement not covered" > try {</span>
1367
+ <span class="cstat-no" title="statement not covered" > fs.writeFileSync(dataFilePath, JSON.stringify(data, null, 2));</span>
1368
+ <span class="cstat-no" title="statement not covered" > return { success: true };</span>
1369
+ } catch (error) {
1370
+ <span class="cstat-no" title="statement not covered" > console.error('Failed to save data:', error);</span>
1371
+ <span class="cstat-no" title="statement not covered" > return { success: false, error: error.message };</span>
1372
+ }
1373
+ });
1374
+ &nbsp;
1375
+ <span class="cstat-no" title="statement not covered" >ipcMain.handle('load-data', <span class="fstat-no" title="function not covered" >as</span>ync () =&gt; {</span>
1376
+ <span class="cstat-no" title="statement not covered" > try {</span>
1377
+ <span class="cstat-no" title="statement not covered" > if (fs.existsSync(dataFilePath)) {</span>
1378
+ const data = <span class="cstat-no" title="statement not covered" >fs.readFileSync(dataFilePath, 'utf-8');</span>
1379
+ <span class="cstat-no" title="statement not covered" > return { success: true, data: JSON.parse(data) };</span>
1380
+ }
1381
+ <span class="cstat-no" title="statement not covered" > return { success: true, data: null };</span>
1382
+ } catch (error) {
1383
+ <span class="cstat-no" title="statement not covered" > console.error('Failed to load data:', error);</span>
1384
+ <span class="cstat-no" title="statement not covered" > return { success: false, error: error.message };</span>
1385
+ }
1386
+ });
1387
+ &nbsp;
1388
+ // Floatnote folder path
1389
+ const floatnoteFolder = <span class="cstat-no" title="statement not covered" >path.join(app.getPath('home'), '.floatnote');</span>
1390
+ &nbsp;
1391
+ // Export note to ~/.floatnote folder
1392
+ <span class="cstat-no" title="statement not covered" >ipcMain.handle('export-to-floatnote', <span class="fstat-no" title="function not covered" >as</span>ync (event, noteData) =&gt; {</span>
1393
+ <span class="cstat-no" title="statement not covered" > try {</span>
1394
+ <span class="cstat-no" title="statement not covered" > console.log('export-to-floatnote called, saving to:', floatnoteFolder);</span>
1395
+ // Create folder if it doesn't exist
1396
+ <span class="cstat-no" title="statement not covered" > if (!fs.existsSync(floatnoteFolder)) {</span>
1397
+ <span class="cstat-no" title="statement not covered" > console.log('Creating folder:', floatnoteFolder);</span>
1398
+ <span class="cstat-no" title="statement not covered" > fs.mkdirSync(floatnoteFolder, { recursive: true });</span>
1399
+ }
1400
+ &nbsp;
1401
+ const filename = <span class="cstat-no" title="statement not covered" >`note-${noteData.id}.json`;</span>
1402
+ const filePath = <span class="cstat-no" title="statement not covered" >path.join(floatnoteFolder, filename);</span>
1403
+ <span class="cstat-no" title="statement not covered" > console.log('Writing file:', filePath);</span>
1404
+ <span class="cstat-no" title="statement not covered" > fs.writeFileSync(filePath, JSON.stringify(noteData, null, 2));</span>
1405
+ <span class="cstat-no" title="statement not covered" > console.log('File written successfully');</span>
1406
+ <span class="cstat-no" title="statement not covered" > return { success: true, path: filePath };</span>
1407
+ } catch (error) {
1408
+ <span class="cstat-no" title="statement not covered" > console.error('Failed to export note:', error);</span>
1409
+ <span class="cstat-no" title="statement not covered" > return { success: false, error: error.message };</span>
1410
+ }
1411
+ });
1412
+ &nbsp;
1413
+ // Open ~/.floatnote folder in Finder
1414
+ <span class="cstat-no" title="statement not covered" >ipcMain.handle('open-floatnote-folder', <span class="fstat-no" title="function not covered" >as</span>ync () =&gt; {</span>
1415
+ <span class="cstat-no" title="statement not covered" > try {</span>
1416
+ // Create folder if it doesn't exist
1417
+ <span class="cstat-no" title="statement not covered" > if (!fs.existsSync(floatnoteFolder)) {</span>
1418
+ <span class="cstat-no" title="statement not covered" > fs.mkdirSync(floatnoteFolder, { recursive: true });</span>
1419
+ }
1420
+ <span class="cstat-no" title="statement not covered" > await shell.openPath(floatnoteFolder);</span>
1421
+ <span class="cstat-no" title="statement not covered" > return { success: true };</span>
1422
+ } catch (error) {
1423
+ <span class="cstat-no" title="statement not covered" > console.error('Failed to open folder:', error);</span>
1424
+ <span class="cstat-no" title="statement not covered" > return { success: false, error: error.message };</span>
1425
+ }
1426
+ });
1427
+ &nbsp;
1428
+ // Export note as PNG with save dialog
1429
+ <span class="cstat-no" title="statement not covered" >ipcMain.handle('export-png', <span class="fstat-no" title="function not covered" >as</span>ync (event, imageDataUrl) =&gt; {</span>
1430
+ <span class="cstat-no" title="statement not covered" > try {</span>
1431
+ const win = <span class="cstat-no" title="statement not covered" >BrowserWindow.fromWebContents(event.sender);</span>
1432
+ &nbsp;
1433
+ // Temporarily disable always-on-top so dialog appears in front
1434
+ <span class="cstat-no" title="statement not covered" > if (win) {</span>
1435
+ <span class="cstat-no" title="statement not covered" > win.setAlwaysOnTop(false);</span>
1436
+ }
1437
+ &nbsp;
1438
+ const result = <span class="cstat-no" title="statement not covered" >await dialog.showSaveDialog(win, {</span>
1439
+ title: 'Export Note as PNG',
1440
+ defaultPath: `floatnote-${Date.now()}.png`,
1441
+ filters: [
1442
+ { name: 'PNG Images', extensions: ['png'] }
1443
+ ]
1444
+ });
1445
+ &nbsp;
1446
+ // Re-enable always-on-top
1447
+ <span class="cstat-no" title="statement not covered" > if (win) {</span>
1448
+ <span class="cstat-no" title="statement not covered" > win.setAlwaysOnTop(true, 'floating', 1);</span>
1449
+ }
1450
+ &nbsp;
1451
+ <span class="cstat-no" title="statement not covered" > if (result.canceled || !result.filePath) {</span>
1452
+ <span class="cstat-no" title="statement not covered" > return { success: false, canceled: true };</span>
1453
+ }
1454
+ &nbsp;
1455
+ // Remove data URL prefix and write file
1456
+ const base64Data = <span class="cstat-no" title="statement not covered" >imageDataUrl.replace(/^data:image\/png;base64,/, '');</span>
1457
+ <span class="cstat-no" title="statement not covered" > fs.writeFileSync(result.filePath, Buffer.from(base64Data, 'base64'));</span>
1458
+ <span class="cstat-no" title="statement not covered" > return { success: true, path: result.filePath };</span>
1459
+ } catch (error) {
1460
+ <span class="cstat-no" title="statement not covered" > console.error('Failed to export PNG:', error);</span>
1461
+ <span class="cstat-no" title="statement not covered" > return { success: false, error: error.message };</span>
1462
+ }
1463
+ });
1464
+ &nbsp;</pre></td></tr></table></pre>
1465
+
1466
+ <div class='push'></div><!-- for sticky footer -->
1467
+ </div><!-- /wrapper -->
1468
+ <div class='footer quiet pad2 space-top1 center small'>
1469
+ Code coverage generated by
1470
+ <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
1471
+ at 2026-01-15T14:08:22.213Z
1472
+ </div>
1473
+ <script src="../prettify.js"></script>
1474
+ <script>
1475
+ window.onload = function () {
1476
+ prettyPrint();
1477
+ };
1478
+ </script>
1479
+ <script src="../sorter.js"></script>
1480
+ <script src="../block-navigation.js"></script>
1481
+ </body>
1482
+ </html>
1483
+