1 |
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> |
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"> |
2 |
<html> |
<html> |
3 |
<head> |
<head> |
4 |
<title>JSCoverage user manual</title> |
<title>JSCoverage user manual</title> |
5 |
<link type="text/css" href="doc.css" rel="stylesheet"> |
<link rel="stylesheet" type="text/css" href="sh_nedit.min.css"> |
6 |
|
<script src="sh_main.min.js"></script> |
7 |
|
<script src="sh_html.min.js"></script> |
8 |
|
<script src="sh_javascript.min.js"></script> |
9 |
|
<link rel="stylesheet" type="text/css" href="doc.css"> |
10 |
</head> |
</head> |
11 |
<body> |
<body onload="sh_highlightDocument();"> |
12 |
|
|
13 |
<h1>JSCoverage user manual</h1> |
<h1>JSCoverage user manual</h1> |
14 |
|
|
15 |
<p> |
<p> |
16 |
JSCoverage is a tool used to measure code coverage in JavaScript |
JSCoverage is a tool that measures code coverage in JavaScript programs. |
|
programs. |
|
17 |
</p> |
</p> |
18 |
|
|
19 |
<p> |
<p> |
20 |
JSCoverage has two components: |
JSCoverage works by adding instrumentation to JavaScript code before it is |
21 |
|
executed in a web browser. JSCoverage provides several alternative ways of doing |
22 |
|
this: |
23 |
</p> |
</p> |
24 |
|
|
25 |
<ol> |
<ul> |
26 |
<li>An executable program which is used to add instrumentation to JavaScript code. |
<li>The simplest method is to use the <code>jscoverage</code> program to generate |
27 |
<li>A web application which is used to execute instrumented code and generate a |
instrumented JavaScript files. |
28 |
code coverage report. |
</li> |
29 |
</ol> |
<li>Alternatively, you can use the <code>jscoverage-server</code> program, a simple web server that instruments |
30 |
|
JavaScript code as it is served. |
31 |
|
</li> |
32 |
|
<li>Finally, <code>jscoverage-server</code> can be run with the <code>--proxy</code> option to |
33 |
|
act as a proxy server which instruments any JavaScript code proxied through it. |
34 |
|
</li> |
35 |
|
</ul> |
36 |
|
|
37 |
|
<p> |
38 |
|
The <code>jscoverage-server</code> program (with or without the <code>--proxy</code> |
39 |
|
option) has the advantage of being able to store coverage reports to the filesystem. |
40 |
|
</p> |
41 |
|
|
42 |
<h2>Installing JSCoverage</h2> |
<h2>Installing JSCoverage</h2> |
43 |
|
|
52 |
</p> |
</p> |
53 |
|
|
54 |
<pre> |
<pre> |
55 |
tar jxvf jscoverage-0.3.tar.bz2 |
tar jxvf jscoverage-0.4.tar.bz2 |
56 |
cd jscoverage-0.3/ |
cd jscoverage-0.4/ |
57 |
./configure |
./configure |
58 |
make |
make |
59 |
</pre> |
</pre> |
60 |
|
|
61 |
<p> |
<p> |
62 |
This will create the <code>jscoverage</code> executable (<code>jscoverage.exe</code> on Windows). |
This will create the <code>jscoverage</code> and <code>jscoverage-server</code> |
63 |
You can install the executable in <code>/usr/local</code> with the command: |
executables (<code>jscoverage.exe</code> and <code>jscoverage-server.exe</code> |
64 |
|
on Windows). You can install the executables in <code>/usr/local</code> with the |
65 |
|
command: |
66 |
</p> |
</p> |
67 |
|
|
68 |
<pre> |
<pre> |
70 |
</pre> |
</pre> |
71 |
|
|
72 |
<p> |
<p> |
73 |
Alternatively, since the program consists of only the single self-contained |
Alternatively, you may simply copy the <code>jscoverage</code> executable and/or |
74 |
<code>jscoverage</code> executable, you may simply copy it to a suitable location |
the <code>jscoverage-server</code> executable to a suitable location in your |
75 |
in your <code>PATH</code>. |
<code>PATH</code>. |
76 |
</p> |
</p> |
77 |
|
|
78 |
<h2>Using JSCoverage</h2> |
<h2>Using the <code>jscoverage</code> program</h2> |
79 |
|
|
80 |
<p> |
<p> |
81 |
Using JSCoverage requires three steps: |
Using the <code>jscoverage</code> program involves the following steps: |
82 |
</p> |
</p> |
83 |
|
|
84 |
<h3>1. Instrumenting code</h3> |
<h3>1. Instrumenting code</h3> |
85 |
|
|
86 |
<p> |
<p> |
87 |
The first step is to add instrumentation to your JavaScript code. This is the function of the |
The first step is to add instrumentation to your JavaScript code. You do this by |
88 |
<code>jscoverage</code> executable. You must provide two arguments: |
executing <code>jscoverage</code> with two arguments: |
89 |
</p> |
</p> |
90 |
|
|
91 |
<pre> |
<pre> |
136 |
which is used to execute the instrumented code. |
which is used to execute the instrumented code. |
137 |
</p> |
</p> |
138 |
|
|
139 |
<h3>2. Running instrumented code in the web application</h3> |
<h3>2. Executing the instrumented code in a web browser</h3> |
140 |
|
|
141 |
<p> |
<p> |
142 |
Open <code>jscoverage.html</code> in your web browser. |
Open <code>jscoverage.html</code> in your web browser. |
151 |
<li>The "About" tab displays information about the current version of JSCoverage. |
<li>The "About" tab displays information about the current version of JSCoverage. |
152 |
</ul> |
</ul> |
153 |
|
|
154 |
<img src="screenshot.png" alt="Screenshot"> |
<p><img src="screenshot.png" alt="Screenshot"></p> |
155 |
|
|
156 |
<p> |
<p> |
157 |
The "Browser" tab contains an <code><iframe></code>, which is initially empty. |
The "Browser" tab contains an <code><iframe></code>, which is initially empty. |
159 |
entering its URL into the "URL" input field. For example, to load |
entering its URL into the "URL" input field. For example, to load |
160 |
the file <code><var>DESTINATION-DIRECTORY</var>/dir/index.html</code>, you can |
the file <code><var>DESTINATION-DIRECTORY</var>/dir/index.html</code>, you can |
161 |
enter the relative URL <code>dir/index.html</code> into the input field. |
enter the relative URL <code>dir/index.html</code> into the input field. |
162 |
|
You can load any page located in <code><var>DESTINATION-DIRECTORY</var>/</code> |
163 |
|
or a subdirectory underneath <code><var>DESTINATION-DIRECTORY</var>/</code>; loading a page |
164 |
|
from outside <code><var>DESTINATION-DIRECTORY</var>/</code>, or from a foreign web |
165 |
|
server, will give unexpected results. |
166 |
</p> |
</p> |
167 |
|
|
168 |
<h3>3. Generating the coverage report</h3> |
<h3>3. Generating a coverage report</h3> |
169 |
|
|
170 |
<p> |
<p> |
171 |
Once the JavaScript code in the page in the "Browser" tab has been executed, click on |
Once the JavaScript code in the page in the "Browser" tab has been executed, click on |
205 |
place an instrumented copy of the code from <code>doc/example</code> in <code>doc/instrumented</code>. |
place an instrumented copy of the code from <code>doc/example</code> in <code>doc/instrumented</code>. |
206 |
</p> |
</p> |
207 |
|
|
208 |
<h3>2. Executing instrumented code</h3> |
<h3>2. Executing the instrumented code in a web browser</h3> |
209 |
|
|
210 |
<p> |
<p> |
211 |
You can load the file <code>doc/instrumented/jscoverage.html</code> in your web browser and type |
You can load the file <code>doc/instrumented/jscoverage.html</code> in your web browser and type |
225 |
firefox "doc/instrumented/jscoverage.html?index.html" |
firefox "doc/instrumented/jscoverage.html?index.html" |
226 |
</pre> |
</pre> |
227 |
|
|
228 |
<img src="screenshot2.png" alt="Screenshot"> |
<p><img src="screenshot2.png" alt="Screenshot"></p> |
229 |
|
|
230 |
<p> |
<p> |
231 |
For this particular page, the JavaScript does not execute automatically: |
For this particular page, the JavaScript does not execute automatically: |
232 |
you have to select one of the radio buttons to execute the code. |
you have to select one of the radio buttons to execute the code. |
233 |
</p> |
</p> |
234 |
|
|
235 |
<img src="screenshot3.png" alt="Screenshot"> |
<p><img src="screenshot3.png" alt="Screenshot"></p> |
236 |
|
|
237 |
<h3>3. Generating the coverage report</h3> |
<h3>3. Generating a coverage report</h3> |
238 |
|
|
239 |
<p> |
<p> |
240 |
Once you have executed the JavaScript code, you are instructed to click on the |
Once you have executed the JavaScript code, you are instructed to click on the |
241 |
"Summary" tab. |
"Summary" tab. |
242 |
</p> |
</p> |
243 |
|
|
244 |
<img src="screenshot4.png" alt="Screenshot"> |
<p><img src="screenshot4.png" alt="Screenshot"></p> |
245 |
|
|
246 |
<p> |
<p> |
247 |
You can click the checkbox to show a list of statements missed during execution. |
You can click the checkbox to show a list of statements missed during execution. |
248 |
</p> |
</p> |
249 |
|
|
250 |
<img src="screenshot5.png" alt="Screenshot"> |
<p><img src="screenshot5.png" alt="Screenshot"></p> |
251 |
|
|
252 |
<p> |
<p> |
253 |
You can click one of the links to get a detailed view of a JavaScript source file. |
You can click one of the links to get a detailed view of a JavaScript source file. |
254 |
</p> |
</p> |
255 |
|
|
256 |
<img src="screenshot6.png" alt="Screenshot"> |
<p><img src="screenshot6.png" alt="Screenshot"></p> |
257 |
|
|
258 |
<h2>Inverted mode</h2> |
<h2>Inverted mode</h2> |
259 |
|
|
272 |
you launch JSCoverage. To do this you need to add some code to your test page: |
you launch JSCoverage. To do this you need to add some code to your test page: |
273 |
</p> |
</p> |
274 |
|
|
275 |
<pre> |
<pre class="sh_javascript"> |
276 |
window.open("path/to/jscoverage.html"); |
window.open('path/to/jscoverage.html'); |
277 |
</pre> |
</pre> |
278 |
|
|
279 |
<p> |
<p> |
288 |
attach it to a button: |
attach it to a button: |
289 |
</p> |
</p> |
290 |
|
|
291 |
<pre> |
<pre class="sh_html"> |
292 |
<button onclick='window.open("path/to/jscoverage.html");'>Coverage report</button> |
<button onclick="window.open('path/to/jscoverage.html');">Coverage report</button> |
293 |
</pre> |
</pre> |
294 |
|
|
295 |
<p> |
<p> |
312 |
report" button to launch the JSCoverage report. |
report" button to launch the JSCoverage report. |
313 |
</p> |
</p> |
314 |
|
|
315 |
<h2>Command line options</h2> |
<h2><code>jscoverage</code> command line options</h2> |
316 |
|
|
317 |
<p> |
<p> |
318 |
The <code>jscoverage</code> program accepts the following options: |
The <code>jscoverage</code> program accepts the following options: |
372 |
(to hide the "Missing" column). By default, the "Missing" column is not displayed. |
(to hide the "Missing" column). By default, the "Missing" column is not displayed. |
373 |
</dl> |
</dl> |
374 |
|
|
375 |
|
<h2>Using the <code>jscoverage-server</code> program</h2> |
376 |
|
|
377 |
|
<p> |
378 |
|
The <code>jscoverage-server</code> program is a simple web server. You can use |
379 |
|
<code>jscoverage-server</code> to serve files from the <code>doc/example/</code> |
380 |
|
directory: |
381 |
|
</p> |
382 |
|
|
383 |
|
<pre> |
384 |
|
cd doc/example |
385 |
|
jscoverage-server --verbose |
386 |
|
</pre> |
387 |
|
|
388 |
|
<p> |
389 |
|
Once the server is running, you can access the JSCoverage web interface by |
390 |
|
visiting the URL <code>http://127.0.0.1:8080/jscoverage.html</code>, and you can |
391 |
|
load the <code>doc/example/index.html</code> file by entering |
392 |
|
<code>index.html</code> in the "URL" input field. (Or you can do this all in |
393 |
|
one step by loading the URL |
394 |
|
<code>http://127.0.0.1:8080/jscoverage.html?index.html</code> in your web |
395 |
|
browser.) The |
396 |
|
<code>jscoverage-server</code> program automatically instruments any served |
397 |
|
JavaScript code, so that code coverage data will be gathered as the code is |
398 |
|
executed in your browser. |
399 |
|
</p> |
400 |
|
|
401 |
|
<p> |
402 |
|
The web interface is slightly different from that generated by the |
403 |
|
<code>jscoverage</code> program: it has a new tab named "Store". |
404 |
|
To store coverage data, click the "Store" tab. |
405 |
|
</p> |
406 |
|
|
407 |
|
<p><img src="screenshot7.png" alt="Screenshot"></p> |
408 |
|
|
409 |
|
<p> |
410 |
|
When you click the "Store" button, the coverage data will be saved to a directory named <code>jscoverage-report/</code>. |
411 |
|
You can view this stored report at any time by opening the file <code>jscoverage-report/jscoverage.html</code> in |
412 |
|
your web browser - you don't need the <code>jscoverage-server</code> running to access it. |
413 |
|
</p> |
414 |
|
|
415 |
|
<p> |
416 |
|
If you use the "Store" tab again to store coverage data, the new data will be merged with |
417 |
|
the previous data in the <code>jscoverage-report/</code> directory. This can be useful, |
418 |
|
for instance, if you wish to run a set of tests in different browsers and generate an |
419 |
|
aggregate report which combines the data for all of them. |
420 |
|
</p> |
421 |
|
|
422 |
|
<p> |
423 |
|
You can stop the server by running another instance of <code>jscoverage-server</code> with the |
424 |
|
<code>--shutdown</code> option: |
425 |
|
</p> |
426 |
|
|
427 |
|
<pre> |
428 |
|
jscoverage-server --shutdown |
429 |
|
</pre> |
430 |
|
|
431 |
|
<h2>Using <code>jscoverage-server --proxy</code></h2> |
432 |
|
|
433 |
|
<p> |
434 |
|
To use <code>jscoverage-server</code> as a proxy server, use the <code>--proxy</code> option: |
435 |
|
</p> |
436 |
|
|
437 |
|
<pre> |
438 |
|
jscoverage-server --verbose --proxy |
439 |
|
</pre> |
440 |
|
|
441 |
|
<p> |
442 |
|
Configure your browser to use an HTTP proxy with address 127.0.0.1 and port 8080. |
443 |
|
You can then generate code coverage data for a web page on the server <code>example.com</code> |
444 |
|
by accessing the JSCoverage web interface at the special URL <code>http://example.com/jscoverage.html</code>. |
445 |
|
Note that this URL is not provided by the <code>example.com</code> server; it is automatically generated |
446 |
|
by the proxy server whenever a URL with path <code>/jscoverage.html</code> is requested. |
447 |
|
</p> |
448 |
|
|
449 |
|
<h2><code>jscoverage-server</code> command line options</h2> |
450 |
|
|
451 |
|
<dl> |
452 |
|
<dt><code>-h</code>, <code>--help</code> |
453 |
|
<dd>Display a brief help message. |
454 |
|
<dt><code>-V</code>, <code>--version</code> |
455 |
|
<dd>Display the version of the program. |
456 |
|
<dt><code>-v</code>, <code>--verbose</code> |
457 |
|
<dd>Explain what is being done. |
458 |
|
<dt><code>--document-root=<var>PATH</var></code> |
459 |
|
<dd>Serve web content from the directory given by <var>PATH</var>. The default is |
460 |
|
the current directory. This option may not be given with the <code>--proxy</code> option. |
461 |
|
<dt><code>--ip-address=<var>ADDRESS</var></code> |
462 |
|
<dd>Run the server on the IP address given by <var>ADDRESS</var>. The default is <code>127.0.0.1</code>. Specify |
463 |
|
<code>0.0.0.0</code> to use any address. |
464 |
|
<dt><code>--no-instrument=<var>URL</var></code> |
465 |
|
<dd>Do not instrument JavaScript code from <var>URL</var>. If you are running <code>jscoverage-server</code> |
466 |
|
with the <code>--proxy</code> option, <var>URL</var> should be a full URL. For example: |
467 |
|
<pre> |
468 |
|
jscoverage-server --proxy --no-instrument=http://example.com/scripts/ |
469 |
|
</pre> |
470 |
|
Without <code>--proxy</code>, <var>URL</var> should be only the path portion of a URL: |
471 |
|
<pre> |
472 |
|
jscoverage-server --no-instrument=/scripts/ |
473 |
|
</pre> |
474 |
|
This option may be given multiple times. |
475 |
|
<dt><code>--port=<var>PORT</var></code> |
476 |
|
<dd>Run the server on the port given by <var>PORT</var>. The default is port 8080. |
477 |
|
<dt><code>--proxy</code> |
478 |
|
<dd>Run as a proxy server. |
479 |
|
<dt><code>--report-dir=<var>PATH</var></code> |
480 |
|
<dd>Use the directory given by <var>PATH</var> for storing coverage reports. The default is |
481 |
|
<code>jscoverage-report/</code> in the current directory. |
482 |
|
<dt><code>--shutdown</code> |
483 |
|
<dd>Stop a running instance of the server. |
484 |
|
</dl> |
485 |
|
|
486 |
|
<h2>Advanced topics</h2> |
487 |
|
|
488 |
|
<h3>Storing coverage reports programmatically</h3> |
489 |
|
|
490 |
|
<p> |
491 |
|
If you are executing a test suite using <code>jscoverage-server</code>, you can |
492 |
|
store a coverage report programmatically by having your test suite call the |
493 |
|
<code>jscoverage_report</code> function (automatically generated by |
494 |
|
<code>jscoverage-server</code>) after all your tests have finished running: |
495 |
|
</p> |
496 |
|
|
497 |
|
<pre class="sh_javascript"> |
498 |
|
if (top.jscoverage_report) { |
499 |
|
top.jscoverage_report(); |
500 |
|
} |
501 |
|
</pre> |
502 |
|
|
503 |
|
<p> |
504 |
|
You can specify the name of the directory in which to store the report by |
505 |
|
passing the name as a parameter to the <code>jscoverage_report</code> function: |
506 |
|
</p> |
507 |
|
|
508 |
|
<pre class="sh_javascript"> |
509 |
|
if (top.jscoverage_report) { |
510 |
|
// determine the directory name based on the browser |
511 |
|
var directory; |
512 |
|
if (/MSIE/.test(navigator.userAgent)) { |
513 |
|
directory = 'IE'; |
514 |
|
} |
515 |
|
else { |
516 |
|
directory = 'other'; |
517 |
|
} |
518 |
|
top.jscoverage_report(directory); |
519 |
|
} |
520 |
|
</pre> |
521 |
|
|
522 |
|
<p> |
523 |
|
This directory will be a subdirectory under the <code>jscoverage-report/</code> |
524 |
|
directory (or whatever is specified with the <code>--report-dir</code> option). |
525 |
|
Using the above example, the report would be stored to either |
526 |
|
<code>jscoverage-report/IE/</code> or <code>jscoverage-report/other/</code>. |
527 |
|
</p> |
528 |
|
|
529 |
|
<h3>Conditional directives</h3> |
530 |
|
|
531 |
|
<p> |
532 |
|
Sometimes you may wish to exclude certain lines of code from coverage |
533 |
|
statistics. Some lines of code may be executed only in certain browsers; other |
534 |
|
lines should never be executed at all (they may be present only to detect |
535 |
|
programming errors). You can use specially formatted comments in your code, |
536 |
|
called <dfn>conditional directives</dfn>, to tell JSCoverage when to exclude |
537 |
|
those lines from coverage statistics. These lines will be ignored in the |
538 |
|
JSCoverage "Summary" tab; in the "Source" tab, these lines will be indicated |
539 |
|
with the color yellow. |
540 |
|
</p> |
541 |
|
|
542 |
|
<p> |
543 |
|
Conditional directives take the following form: |
544 |
|
</p> |
545 |
|
|
546 |
|
<pre class="sh_javascript"> |
547 |
|
//#JSCOVERAGE_IF <var>CONDITION</var> |
548 |
|
... |
549 |
|
//#JSCOVERAGE_ENDIF |
550 |
|
</pre> |
551 |
|
|
552 |
|
<p> |
553 |
|
The <var>CONDITION</var> is an ordinary JavaScript expression; if this |
554 |
|
expression evaluates to <code>true</code>, then the lines of code between the |
555 |
|
<code>//#JSCOVERAGE_IF</code> and <code>//#JSCOVERAGE_ENDIF</code> directives are |
556 |
|
included in coverage statistics; otherwise, they are excluded from coverage |
557 |
|
statistics. |
558 |
|
</p> |
559 |
|
|
560 |
|
<p> |
561 |
|
In order to be recognized as a conditional directive, the comment must be |
562 |
|
formatted exactly as shown: it must be a line comment starting with <code>//</code>, |
563 |
|
it must start in the first column, and it must be followed by <code>#JSCOVERAGE_IF</code> |
564 |
|
or <code>#JSCOVERAGE_ENDIF</code> in uppercase letters with no intervening white space. |
565 |
|
</p> |
566 |
|
|
567 |
|
<p> |
568 |
|
For example, if you have some code in an <code>if</code> statement which is |
569 |
|
executed only in certain browsers, you can usually just repeat the condition in |
570 |
|
a <code>//#JSCOVERAGE_IF</code> directive: |
571 |
|
</p> |
572 |
|
|
573 |
|
<pre class="sh_javascript"> |
574 |
|
if (window.ActiveXObject) { |
575 |
|
//#JSCOVERAGE_IF window.ActiveXObject |
576 |
|
return new ActiveXObject('Msxml2.XMLHTTP'); |
577 |
|
//#JSCOVERAGE_ENDIF |
578 |
|
} |
579 |
|
</pre> |
580 |
|
|
581 |
|
<p> |
582 |
|
Alternatively, it may be easier to diagnose problems if you specify exactly |
583 |
|
which browsers you expect to execute the code in the conditional: |
584 |
|
</p> |
585 |
|
|
586 |
|
<pre class="sh_javascript"> |
587 |
|
if (window.ActiveXObject) { |
588 |
|
//#JSCOVERAGE_IF /MSIE/.test(navigator.userAgent) |
589 |
|
return new ActiveXObject('Msxml2.XMLHTTP'); |
590 |
|
//#JSCOVERAGE_ENDIF |
591 |
|
} |
592 |
|
</pre> |
593 |
|
|
594 |
|
<p> |
595 |
|
To exclude code from coverage statistics unconditionally, you can use <code>//#JSCOVERAGE_IF 0</code> or |
596 |
|
<code>//#JSCOVERAGE_IF false</code>: |
597 |
|
</p> |
598 |
|
|
599 |
|
<pre class="sh_javascript"> |
600 |
|
function f(s) { |
601 |
|
if (typeof(s) !== 'string') { |
602 |
|
//#JSCOVERAGE_IF 0 |
603 |
|
throw 'function f requires a string argument'; |
604 |
|
//#JSCOVERAGE_ENDIF |
605 |
|
} |
606 |
|
} |
607 |
|
</pre> |
608 |
|
|
609 |
<h2>Caveats</h2> |
<h2>Caveats</h2> |
610 |
|
|
611 |
<ul> |
<ul> |
620 |
statements, you may get strange results. |
statements, you may get strange results. |
621 |
<li>JSCoverage uses frames. Some web pages that use frames may not function properly when run under JSCoverage, especially |
<li>JSCoverage uses frames. Some web pages that use frames may not function properly when run under JSCoverage, especially |
622 |
those which try to access the top-level frame (<code>window.top</code>, <code>target="_top"</code>, etc.). |
those which try to access the top-level frame (<code>window.top</code>, <code>target="_top"</code>, etc.). |
623 |
<li>JSCoverage is alpha software. Use at your own risk. |
<li>JSCoverage is distributed without any warranty. See the <a href="license.html">license</a> for more details. |
624 |
</ul> |
</ul> |
625 |
|
|
626 |
<address> |
<address> |
627 |
Copyright © 2007 siliconforks.com<br> |
Copyright © 2007, 2008 <a href="http://siliconforks.com/"><img src="siliconforks-16x16.png" width="16" height="16" class="icon" alt="Silicon Forks"></a> <a href="http://siliconforks.com/">siliconforks.com</a><br> |
628 |
Last updated August 26, 2007<br> |
Last updated September 12, 2008<br> |
629 |
<a href="mailto:jscoverage@siliconforks.com">jscoverage@siliconforks.com</a> |
<a href="mailto:jscoverage@siliconforks.com">jscoverage@siliconforks.com</a> |
630 |
</address> |
</address> |
631 |
|
|