forked from ianb/doctestjs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathreference.html
598 lines (410 loc) · 24.1 KB
/
reference.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
<!DOCTYPE html>
<html class="no-js">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="doctest.css">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Doctest.js: The Reference</title>
<meta name="description" content="Doctest.js is a Javascript testing framework">
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" href=".resources/boilerplate/css/normalize.min.css">
<link rel="stylesheet" href=".resources/boilerplate/css/main.css">
<link rel="stylesheet" href=".resources/doc.css">
<script src=".resources/boilerplate/js/vendor/modernizr-2.6.1.min.js"></script>
<script src="doctest.js"></script>
<!-- EXTRA_HEAD -->
<script type="text/javascript" src="./.resources/toc.js"></script>
<!-- /EXTRA_HEAD -->
</head>
<body class="autodoctest">
<div class="header-container">
<header class="wrapper clearfix">
<h1 class="title"><a href="/">Doctest.js</a>: <!-- TITLE -->The Reference<!-- /TITLE --></h1>
<nav>
<ul>
<li><a href="https://github.com/ianb/doctestjs">Github</a></li>
<li><a href="/reference.html">Reference</a></li>
<li><a href="/tutorial.html">Tutorial</a></li>
</ul>
</nav>
</header>
</div>
<div class="main-container">
<div class="main wrapper clearfix">
<!-- BODY -->
<p>
Author: Ian Bicking,
<a href="mailto:[email protected]">[email protected]</a>
</p>
<div id="contents"></div>
<h3 id="html">HTML page</h3>
<p>Your HTML page needs just a couple things to set it up for a test:
<pre>
<html>
<head>
<script src="doctestjs/doctest.js"></script>
<link href="doctestjs/doctest.css" rel="stylesheet">
</head>
<body class="autodoctest">
<pre class="test / doctest">
test
</pre>
</body>
</html>
</pre>
</p>
<p>Notably you need <code><body <strong>class="autodoctest"</strong>></code> to get the tests to run automatically on page load. If you were invoking doctest explicitly (like is done on the <a href="try.html">Try It</a> page) then you might leave this off.</p>
<h4 id="external">External code</h4>
<p>Often you won't want to write your test code inside the test itself. Instead you'll want to put it in its own <code>.js</code> file. Especially with <a href="#format-test"><code>test</code></a> the code is valid Javascript, and you will probably want syntax highlighting and all that.</p>
<p>To do this, use an <code>href</code> attribtue on your <code><pre></code> element, like:
<pre>
<pre class="test" href="./tests.js"></pre>
</pre>
The contents of the element don't matter. The test will be loaded from that location (which could be a full URL but you'll probably have <a href="http://www.w3.org/TR/cors/">cross-origin</a> errors if you tried that — this doesn't use <code><script></code> tags to load those scripts, it uses XMLHttpRequest). Note that the class is still required!</p>
<p>You can also load it from a variable location, using query string parameters to find the file. The most common pattern would be like this:
<pre>
<pre class="test" data-href-pattern="./{test-name|default.js}"></pre>
</pre>
Any URL parameters (like <code>{test-name}</code>) get filled in by the query string (<code>?test-name=example.js</code>). By default these values can only contain letters, numbers, <code>_</code>, <code>-</code> and <code>.</code> — this is to protect against loading scripts from unexpected locations via an implicitly unsafe parameters in the query string.</p>
<p>If you want to use a different restriction on a variable name, use <code>{variable-name:regular_expression}</code> — and use <code>^</code> and <code>$</code> to make sure to match the entire string.</p>
<p>If you want a default (if the parameter isn't set or is empty) use <code>|</code> to separate out the default. The default should come after the regular expression. In the example the default is <code>default.js</code>. Don't use extra spaces around <code>|</code>!</p>
<p>Note this works well with relative addresses like <code><a href="?test-name=foo.js">foo.js</a></code></p>
<h3 id="format">Format of test</h3>
<p>There are two formats that a doctest can take. You've probably seen the <code>test</code> format, there is also the more traditional <code>doctest</code> format.</p>
<h4 id="format-doctest"><code>doctest</code> format</h4>
<p>This format is used like:
<pre>
<pre class="doctest">
$ first_line();
> continuation line
output
</pre>
</pre>
</p>
<p>The first line of course starts wtih <code>$</code> and a space. Think of it like a Unix command line. And also similar to a command line shell the continuation line is <code>></code>. Any line <em>without</em> a leading <code>$</code> or <code>></code> is considered expected output.</p>
<p>Note you can still have multiple statements using a continuation line. The only difference between two lines with <code>$</code> and one with a <code>$</code> followed by <code>></code> is that in the latter case the two lines are executed <em>together</em> and the output from both is combined into what is expected.</p>
<h4 id="format-test"><code>test</code> format</h4>
<p>In this format the expected output is in a comment, like:
<pre>
<pre class="test">
statement_1();
statement_2();
// Some other comment
// => expected output
More statements
/* =>
expected output
*/
</pre>
</p>
<p>Basically the test is split up by using the <code>// =></code> comments. Each chunk is executed independently, and the test may be paused at the point where the expected output is found.</p>
<h4 id="sections">Test sections</h4>
<p><em>If</em> you are using <a href="#external">external test code</a> (and <code>test</code>) you can include <em>section headers</em> like:
<pre>
// == SECTION A section header
</pre>
</p>
<p>You can have one or more <code>=</code>'s. The text <code>A section header</code> will become a header. Each section header turns into a new <code><pre></code> element.</p>
<h4 id="compact">Compact <code><pre></code>'s</h4>
<p>Sometimes you'll have boilerplate code that sets up the test environment, and you'll be uninterested in that code (unless it fails). This might define helper functions, or run some really routine sanity tests. You can use this to make those test blocks small:
<pre>
<pre class="test expand-on-failure">
...
</pre>
</pre>
This will make the test 3em tall unless there's a failure, at which point it expands to its full size.</p>
<p>You can use <code>// =SECTION Section Title expand-on-failure</code> to make the section compact except in case of failure.</p>
<h3 id="print">Printing/writing</h3>
<p>The <code>print()</code> function is pretty important, of course. (Note it also was called <code>writeln()</code>, a name which is still supported).</p>
<p><code>print()</code> will print out any strings given to it, and the <code>repr()</code> of any other objects, with a space between each argument.</p>
<p>You can make a <strong>custom <code>repr()</code></strong> for any object by adding a <code>.repr()</code> method. It should look like:
<pre>
MyObject.prototype.repr = function () {
return '[MyObject attr: ' + repr(this.attr) + ']';
};
</pre>
</p>
<p>If you can't add a method to your object, you can also add a stringifier using <code>repr.register()</code>.</p>
<p>You might do this like:
<pre>
repr.register(
function (o) {
return o instanceof MyClass;
},
function (o, indentString) {
return '[MyClass attr: ' + repr(o.attr) + ']';
}
);
</pre>
The first function is a <em>test</em> that is applied to objects. If it returns true, then the second function is called to stringify the object. <em>If</em> your representation uses multiple lines, then you should indent subsequent lines with the string, like <code>return '[Beginning\n' + indentString + ' end\n' + indentString + ']';</code>. The beginning is never indented.
</p>
<p>Some of the objects that have custom representations:</p>
<dl>
<dt>XML and DOM objects</dt>
<dd>These are displayed as the normal serialization, e.g., <code><input type="text" /></code>. XML-style endings for empty tags are always used. Attributes are alphabetized. HTML tags are upppercase and attributes are lowercase, because the DOM seems to like that.</dd>
<dt>XMLHttpRequest</dt>
<dd>These are displayed like <code>[XMLHttpRequest STATE [STATUS]]</code>. The <code>STATE</code> is one of <code>UNSENT</code>, <code>OPENED</code>, <code>HEADERS_RECEIVED</code>, <code>LOADING</code> and <code>DONE</code>. The <code>[STATUS]</code> is only displayed if the request has finished.</dd>
</dl>
<p>Arrays and objects are displayed like you'd think. This might include objects that you might not think of as "plain" objects. Also the object prototype is not displayed. You'll have to use something like <code>print(o.constructor)</code> if you want to be specific about classes.</p>
<h4 id="console"><code>console.log()</code></h3>
<p><code>console.log()</code> works a lot like <code>print()</code>. But unlike <code>print()</code> it doesn't make a test pass or fail, it's purely informative.</p>
<p>All the methods on console should work, like <code>console.warn()</code>. The underlying normal console function is called, but in addition on a test-by-test basis these are collected and displayed.</p>
<p><code>console.clear()</code> also works, and can be useful especially if you need to loop over cases, but only see the console messages for a case that fails. Like:
<pre>
for (var i=0; i<100; i++) {
// runRandomTest() has a bunch of calls to console.log():
result = runRandomTest();
if (result.got != result.expected) {
print("Error:", result.got, "!=", result.expected);
throw 'Error';
} else {
// Everything went fine, console.log messages are boring...
console.clear();
}
}
</pre>
<h4 id="printResolved"><code>printResolved()</code> for Deferred and Promises</h4>
<p>There's special support for the jQuery <a href="http://api.jquery.com/category/deferred-object/">Deferred</a> object, and generally <a href="http://wiki.commonjs.org/wiki/Promises/A">Promises/A</a>.</p>
<p>This support is through the <code>printResolved()</code> function, which is basically equivalent to <code>print()</code> except any promise arguments will be waited on to resolve (proper resolution or an error). You can use it like this:</p>
<pre class="test">
var def = $.Deferred();
setTimeout(function () {
def.resolve("Resolved!");
});
printResolved(def);
// => Resolved!
</pre>
<p>Errors are printed out with <code>Error:</code> before the value, and multiple arguments are printed out with spaces between them, or a placeholder if there's no arguments. For instance:</p>
<pre class="test">
var def = $.Deferred();
def.reject({code: 1}, "a message");
printResolved(def);
// => Error: {code: 1} a message
// Or you might not have any value at all:
def = $.Deferred();
def.resolve();
printResolved(def);
// => (resolved)
</pre>
<h3 id="matching">Output matching</h3>
<p>The <em>expected</em> output is compared with the output you actually <em>got</em> (received).</p>
<p>First all whitespace is normalized. Empty lines are removed from both sides. Leading spaces are removed (i.e., indentation does not matter). Multiple spaces are normalized to a single space.</p>
<p>There are two wildcard patterns. Ellipsis — <code>...</code> — means "match anything". This will match zero character, or multiple lines. You should be careful about matching <em>too</em> much.</p>
<p>The shorter wildcard is <code>?</code>. This matches letters, numbers, underscore, period, and question mark. Note if you want to match a string with such characters you might have to use <code>"?"</code>.</p>
<p>Also a special case, <code>"</code> matches <code>'</code> and vice versa. Since in most contexts these mean the same thing, this lets you be agnostic.</p>
<p>When you have a large expected text and got a lot of text, and that text differs just a bit, you'll see a line-by-line comparison of the two, to help you identify exactly where the problem is. Note if you use wildcards the line-by-line comparison might be very inaccurate.</p>
<h3 id="wait"><code>wait()</code>, async code, and pausing the tests</h3>
<p>Often you'll want to let code run for a while on its own before you are done with testing a section of code. I.e., you want to let all the requests complete, DOM elements update, and so forth.</p>
<p>Each <em>section</em> of code can be paused at the end. <strong>Code cannot be paused in the middle of a section.</strong> So before the output (i.e., before <code>// =></code>) the test runner can wait and collect output.<p>
<p>Anytime you call <code>wait()</code> inside a section of code it tells the test runner to wait <em>at the end of the test</em>, either until some condition is true or until some time has passed. If the condition doesn't complete an error/timeout message is <code>print()</code>'d.</p>
<p>A half baked version of what happens is this:
<pre>
var printed = [], waiting = null;
function print(arg) {
printed.push(arg);
}
function wait(condition) {
waiting = condition;
}
function checkOutput() {
if (printed.join('\n') != expectedOutput) {
fail();
}
}
eval(exampleCode);
hardTimeout = 5000; // 5 seconds
checkTime = 100; // check every 0.1 seconds
if (waiting === null) {
checkOutput();
} else if (typeof waiting == "number") {
setTimeout(checkOutput, waiting);
} else {
var now = Date.now();
function checker() {
if (waiting()) {
checkOutput();
} else if (Date.now() - now > hardTimeout) {
print("Error: timed out");
checkOutput();
} else {
setTimeout(checker, hardTimeout);
}
}
setTimeout(checker, 0);
}
</pre>
Now you practically know how to write doctest yourself!
</p>
<p>Specifically this is how you can run <code>wait()</code>:</p>
<dl>
<dt><code>wait()</code></dt>
<dd>This makes the test pause just for a moment. It's the same as <code>wait(0)</code>.</dd>
<dt><code>wait(milliseconds)</code></dt>
<dd>This forces the test to pause for the given number of milliseconds. Everything is always in milliseconds.</dd>
<dt><code>wait(condition)</code></dt>
<dd>This calls <code>condition()</code> frequently until it returns true.</dd>
<dt><code>wait(condition, timeout)</code></dt>
<dd>This calls condition up until <code>timeout</code> milliseconds. You can use this to extend the timeout. The default timeout is 5 seconds (5000).</dd>
</dl>
<h3 id="spy">Spy, mocking, and watching functions</h3>
<p><code>Spy</code> is used to create a mock object/function that can be used to track calls and inspect call order and arguments.</p>
<p>The basic use is like this:
<pre class="test">
func = Spy('func');
func(1, 2, 3);
obj = {a: 1, func: func};
obj.func();
/* =>
func(1, 2, 3)
{a: 1, func: Spy('func')}.func()
*/
</pre>
</p>
<p>That is, every time the Spy is called it will print out the call, all its arguments, and if there was a bound <code>this</code> (as in the <code>obj.func()</code> example) then that value will be displayed as well.</p>
<p>Each spy is <em>named</em>, and if you call <code>Spy(name)</code> with a name that has been used before you will get the same Spy object back.</p>
<p><code>Spy</code> can be invoked in a couple ways:</p>
<dl>
<dt><code>Spy(name)</code></dt>
<dd>Just creates/gets the Spy with the given name.</dd>
<dt><code>Spy(name, {options})</code></dt>
<dd>Create the Spy with some options (as described below)</dd>
<dt><code>Spy(name, function () {...})</code></dt>
<dd>Creates a Spy that wraps another function that you provide. The Spy will be called first, and will print out the call, and then it will call the sub-function with the same arguments and <code>this</code>.</dd>
<dt><code>Spy(name, function () {...}, {options})</code></dt>
<dd>Create a Spy that wraps a function and has extra options.</dd>
</dl>
<p>Note that your function can raise an exception, and the Spy will pass it through (though also note the exception using <code>console.log()</code>). You can use this to inspect how a library reacts to exceptions in callbacks.</p>
<h4 id="spy-options">Spy options</h4>
<p>The options available:</p>
<dl>
<dt><code>applies: function () {...}</code></dt>
<dd>This is the function that will be called when the Spy is called. It's the same as passing in the function as the second argument.</dd>
<dt><code>writes: false</code> (default <code>true</code>)</dt>
<dd>If this is false (default true) then it will <em>not</em> print out the call.</dd>
<dt><code>returns: value</code> (default <code>undefined</code>)</dt>
<dd>This is what the Spy returns when called (assuming you did not use <code>applies</code>). By default it simply returns <code>undefined</code>, which is what a function returns when you have no explicit <code>return</code> statement.</dd>
<dt><code>throwError: exceptionObject</code></dt>
<dd>If given, when the Spy is called it'll do <code>throw exceptionObject</code></dd>
<dt><code>ignoreThis: true</code> (default <code>false</code>)</dt>
<dd>If true, then <code>this</code> won't be printed out regardless of whether it is bound. This is useful when a library binds <code>this</code> carelessly.</dd>
<dt><code>wrapArgs: true</code> (default <code>false</code>)</dt>
<dd>If true then wrapping will be forced when the arguments are printed out. Otherwise wrapping is only applied if an argument is longer than 80 columns (the default for printing generally).</dd>
<dt><code>wait: true</code> (default <code>false</code>)</dt>
<dd>This is equivalent to calling <code>Spy(name).wait()</code>. You can also pass in a number, which will be the millisecond timeout, e.g., <code>Spy(name, {wait: 10000})</code> to wait for 10 seconds for the Spy to be called.</dd>
<dt><code>methods: {...}</code></dt>
<dd>Equivalent to calling <code>Spy.methods({...})</code>. See below for details.</dd>
</dl>
<p>You can also change <code>Spy.defaultOptions</code> if you want to override one option by default, for instance to turn off printing or ignore <code>this</code>.</p>
<h4 id="spy-methods">Spy methods</h4>
<p>Several methods are available:</p>
<dl>
<dt><code>Spy().wait([timeout])</code></dt>
<dd>This makes the test pause until the Spy has been called. Sometimes you <em>must</em> use the method instead of <code>Spy(name, {wait: true})</code>. An example:
<pre>
SomeAPI.onload = Spy('SomeAPI.onload', function (data) {
SomeOtherAPI.save(data, Spy('SomeOtherAPI.save'));
};
Spy('SomeOtherAPI.save').wait();
/* =>
SomeAPI.onlaod({...})
SomeOtherAPI.save()
*/
</pre>
In this case the Spy is created <em>inside</em> another method, and that method is not called right away. <code>wait: true</code> doesn't work in this case. Instead you should call <code>Spy(name).wait()</code> later. Since names are unique, this will be the same Spy object as referenced earlier.
</dd>
<dt><code>Spy.on("obj.attr", [applies/options])</code></dt>
<dd>This replaces the attribute <code>attr</code> on the object <code>obj</code> with a Spy. The object must be defined at the top level (i.e., <code>eval("obj")</code> must return the object). This is basically the same as:
<pre>
obj = eval("obj");
spy = Spy("obj.attr", [applies/options]);
obj.attr = spy;
</pre>
</dd>
<dt><code>Spy.on(obj, "obj.attr", [applies/options])</code></dt>
<dd>This is the same as the previous form, except for use when <code>obj</code> is not a global variable.</dd>
<dt><code>aSpy.formatCall()</code></dt>
<dd>When the Spy is called, generally this does:
<pre>
print(aSpy.formatCall());
</pre>
If you use <code>writes: false</code> then this might be helpful.
</dd>
<dt><code>aSpy.method("methodName", [applies/options])</code></dt>
<dd>This creates an attribute <code>aSpy.methodName</code> and assigns a Spy to that attribute. You may give the normal constructor arguments.</dd>
<dt><code>aSpy.methods({methodName: [true or options], ...})</code></dt>
<dd>This creates multiple attributes at once. You may use <code>{methodName: true}</code> if you have no options to pass in.</dd>
</dl>
<h4 id="spy-attributes">Spy attributes</h4>
<p>Spies have several attributes to inspect how they have been called:</p>
<dl>
<dt><code>aSpy.self</code> and <code>aSpy.selfList</code></dt>
<dd>This is the value of <code>this</code> as the spy was called. As the spy is called multiple times each <code>this</code> value is appended to <code>selfList</code>, forming a history.</dd>
<dt><code>aSpy.args</code> and <code>aSpy.argList</code></dt>
<dd>This is the list of arguments that the function was called with. <code>.argList</code> gives the history of past calls.</dd>
</dl>
<h3 id="abort">Aborting your tests</h3>
<p>Tests often has prerequesites. Perhaps some browsers aren't supported. Maybe you need a server setup. Normally doctest will run through all the tests regardless of failures, but when basic prerequesites are missing this creates lots of chatter and failures with no purpose.</p>
<p>To stop the tests from running call <code>Abort()</code>. This will still run the rest of the test block (up until the next <code>// =></code>).</p>
<h3 id="jshint">jshint</h3>
<p>A helper is provided to help you run <a href="http://www.jshint.com/">JSHint</a> regularly on your code. Just do this:</p>
<pre>
jshint("source-filename.js", [jshint options]);
</pre>
<p>You can give a full URL, but you can also just give the filename. When given a filename then all the <code><script></code> tags are searched for that filename. The source is fetched and JSHint is run on that source.</p>
<p>You may <a href="http://www.jshint.com/docs/">give options to suppress or enforce checks</a>. In addition you may list the known issues that you wish to ignore: issues are printed out in order, and are matched like any other text. You might want to use this to simply see the errors without checking them for anything in paticular:
<pre>
jshint("source-filename");
// => ...
</pre>
</p>
<h3 id="nosyxmlhttprequest"><code>NosyXMLHttpRequest</code></h3>
<p>Sometimes you may want to watch the progress of XMLHttpRequest requests — both how the request is constructed and its result. You can use <code>NosyXMLHttpRequest</code> to wrap request objects.</p>
<p>You probably want to use it like:
<pre>
XMLHttpRequest = NosyXMLHttpRequest.factory("request");
</pre>
</p>
<p>The name will be used when showing output (e.g., <code>request.setRequestHeader('X-Something', 'value')</code>).</p>
<h3 id="node">Node.js</h3>
<p>Doctest.js has some Node support. You must use the <a href="#format-test">comment-based test format</a> in stand-alone Javascript files. Then:</p>
<pre>
$ npm install -g doctestjs
$ doctest test.js
</pre>
<p>This will print a success or failure message, and will exit with a code (the number of failures) if the test does not pass.</p>
<p>If you do not wish to install the package globally, do:</p>
<pre>
$ npm install doctestjs
$ node_modules/.bin/doctest test.js
</pre>
<div style="display: none">
<!-- This is where the summary goes, which we basically want to hide
on this page: -->
<div id="doctest-output"></div>
</div>
<!-- /BODY -->
</div> <!-- #main -->
</div> <!-- #main-container -->
<div class="footer-container">
<footer class="wrapper">
<h3 class="no-toc">doctest.js is by <a href="http://ianbicking.org">Ian Bicking</a>.
It's on <a href="https://github.com/ianb/doctestjs">github</a>!</h3>
</footer>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
<script>
window.jQuery || document.write('<script src=".resources/boilerplate/js/vendor/jquery-1.8.1.min.js"><\/script>')
</script>
<script src=".resources/boilerplate/js/main.js"></script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-34921728-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</body>
</html>