Skip to content
Newer
Older
100644 660 lines (439 sloc) 21.8 KB
7ebac17 @ianb deployment 2b9f804
authored
1 <!DOCTYPE html>
2 <html class="no-js">
3 <head>
4 <meta charset="utf-8">
5 <link rel="stylesheet" href="doctest.css">
6 <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
7 <title>A doctest.js tutorial</title>
8 <meta name="description" content="Doctest.js is a Javascript testing framework">
9 <meta name="viewport" content="width=device-width">
10 <link rel="stylesheet" href="resources/boilerplate/css/normalize.min.css">
11 <link rel="stylesheet" href="resources/boilerplate/css/main.css">
12 <link rel="stylesheet" href="resources/doc.css">
13 <script src="resources/boilerplate/js/vendor/modernizr-2.6.1.min.js"></script>
14 <script src="doctest.js"></script>
15 <!-- EXTRA_HEAD -->
16 <script type="text/javascript" src="./resources/toc.js"></script>
17 <!-- /EXTRA_HEAD -->
18 </head>
19 <body class="autodoctest">
20
21 <div class="header-container">
22 <header class="wrapper clearfix">
23 <h1 class="title"><a href="/">Doctest.js</a>: <!-- TITLE -->A Tutorial <!-- /TITLE --></h1>
24
25 <nav>
26 <ul>
27 <li><a href="https://github.com/ianb/doctestjs">Github</a></li>
28 <li><a href="/reference.html">Reference</a></li>
29 <li><a href="/tutorial.html">Tutorial</a></li>
30 </ul>
31 </nav>
32
33 </header>
34 </div>
35
36 <div class="main-container">
37 <div class="main wrapper clearfix">
38
39
40 <!-- BODY -->
41
734197c @ianb deployment c824fca
authored
42
43 <aside>
44 <h3>Try it now!</h3>
45
46 <p>If you want to try writing/running your own tests (maybe as you read the tutorial) try the <strong><a href="try.html">live demo</a></strong>.
47 </p>
48 </aside>
49
7ebac17 @ianb deployment 2b9f804
authored
50 <div id="contents"></div>
51
52 <article>
53 <section id="introduction">
54 <header>
21c2592 @ianb deployment 436751e
authored
55 <h1 id="intro">What's it like?</h1>
7ebac17 @ianb deployment 2b9f804
authored
56 </header>
57
58 <p>
59
60 So you've decided to finally get religion when it comes to testing your Javascript code? Or, you feel like testing just isn't as easy as it could be, and want to find a better way to test your Javascript code? Or even: you've thought about or tried doing Test Driven Development but you've found it hard to get going? Let's do this...
61
62 </p>
63
64 <p>
65
66 Doctest.js is basically <em>example code</em> and then <em>expected output</em>. This is really what most tests look like, but instead of lots of <code>assertEqual(example, expected)</code> this example/expected combination is embedded into the structure of the test.
67
68 </p>
69
70 <aside>
21c2592 @ianb deployment 436751e
authored
71 <h3 id="page-setup">Page Setup</h3>
7ebac17 @ianb deployment 2b9f804
authored
72
73 <p>
74 See <a href="#html">Setting Up Your HTML</a> to see how to get your test running in the browser.
75 </p>
76 </aside>
77
78 <p>
79
80 I'm going to get right into how the test code looks, but to actually <em>use</em> doctest.js you have to setup an HTML file in a specific format. That is described later in the <a href="#html">HTML section</a>.
81
82 </p>
83
84 <p>
85
86 The structure looks like something you've probably seen before. We add one new function, <code>print()</code>, that works a lot like <code>console.log()</code>. Then we have a comment that shows what we expect to be output. A really simple example:
87
b315102 @ianb deployment 786516a
authored
88 <pre class="test">
7ebac17 @ianb deployment 2b9f804
authored
89 function factorial(n) {
90 if (typeof n != "number") {
91 throw "You must give a number";
92 }
93 if (n <= 0) {
94 return 1;
95 }
96 return n * factorial(n-1);
97 }
98
99 print(factorial(4))
100 // => 25
101 </pre>
102
103 </p>
104
105 <p>
106
107 See what I did there? 25 is totally the wrong answer! Also see what happened, the test just ran and told us so! There's also a summary of all the tests; if you do nothing it shows up at the top of the page, but in the interest of introducing the summary, here it is:
108
109 </p>
110
111 <p id="doctest-output" style="border: 1px solid #999"></p>
112
113 <p>
114
115 You'll notice it shows a failure (or more than one &mdash; it's the summary for all the examples in this tutorial). It also has a link to each failure, so you can jump to the problematic section.
116
117 </p>
118
119 <aside>
21c2592 @ianb deployment 436751e
authored
120 <h3 id="quoting">Quoting</h3>
7ebac17 @ianb deployment 2b9f804
authored
121
122 <p>
123 If you are writing your tests inline in the document, remember that you don't need to quote <code>></code> as <code>&amp;gt;</code>, that's only needed for <code>&lt;</code>
124 </p>
125 </aside>
126
127 <p>
128
129 Let's look at what we did there: <code>print(factorial(4))</code> and <code>// => 25</code> &mdash; the output is just a comment that starts with <code>=></code>.
130
131 </p>
132
133 </section>
134
135 <section id="errors">
136 <header>
21c2592 @ianb deployment 436751e
authored
137 <h3 id="errors">Testing for error conditions</h3>
7ebac17 @ianb deployment 2b9f804
authored
138 </header>
139
140 <p>
141
142 You can also test errors:
143
b315102 @ianb deployment 786516a
authored
144 <pre class="test">
7ebac17 @ianb deployment 2b9f804
authored
145 print(factorial(null));
146 // => Error: You must give a number
147 </pre>
148
149 When an exception is thrown it will print out <code>Error: (error text)</code> which you can match against. This way you can test for error conditions just like you test how "correct" invocations work. Note that the <code>print()</code> isn't really necessary here, you could do this just as well:
150
b315102 @ianb deployment 786516a
authored
151 <pre class="test">
7ebac17 @ianb deployment 2b9f804
authored
152 factorial(null);
153 // => Error: You must give a number
154 </pre>
155
156 </p>
157
158 </section>
159
160 <section id="print">
161 <header>
21c2592 @ianb deployment 436751e
authored
162 <h3 id="print"><code>print()</code> and output matching</h3>
7ebac17 @ianb deployment 2b9f804
authored
163 </header>
164
165 <aside>
166 <p>For more detail on printing see <a href="reference.html#print">the reference</a>.</p>
167 </aside>
168
169 <p>
170
171 <code>print()</code> pretty-prints things. This is important, because you have to "expect" the same output that <code>print()</code> produces. You can give multiple arguments, like with <code>console.log</code>.
172
b315102 @ianb deployment 786516a
authored
173 <pre class="test">
7ebac17 @ianb deployment 2b9f804
authored
174 print({someProperty: 123, something: {a: 1, b: 2}, "foo": 123.1032, "another-property": [1,2,3,4]});
175 /* =>
176 {
177 "another-property": [1, 2, 3, 4],
178 foo: 123.1032,
179 someProperty: 123,
180 something: {a: 1, b: 2}
181 }
182 */
183 </pre>
184
185 You might notice that the attributes are alphabetized and are quoted only when necessary. If it's a small object it stays on one line:
186
b315102 @ianb deployment 786516a
authored
187 <pre class="test">
7ebac17 @ianb deployment 2b9f804
authored
188 print({someProperty: 123});
189 // => {someProperty: 123}
190 </pre>
191
192 </p>
193
194 <p>
195
196 But sometimes the output is unpredictable; or rather you can predict it will change. When that's the case you can basically put a wildcard in the expected output: <code>...</code> &mdash; that will match anything, including multiple lines. In addition you can use <code>?</code> to match one word-like-thing (a number, symbol, etc; not <code>&quot;</code> or whitespace or other symbols). You can use it like this:
197
b315102 @ianb deployment 786516a
authored
198 <pre class="test">
7ebac17 @ianb deployment 2b9f804
authored
199 print({
200 date: new Date(),
201 timestamp: Date.now()
202 });
203
204 // => {date: ..., timestamp: ?}
205 </pre>
206
207 </p>
208
209 <p>
210
211 You might notice that it <em>passes</em>, but you still get to see the actual output. This is a great way to show information that you can review, without actually testing. For instance, you might be testing something that connects to a server, in that case you might want to do this:
212
b315102 @ianb deployment 786516a
authored
213 <pre class="test">
7ebac17 @ianb deployment 2b9f804
authored
214 var server = {url: "http://localhost:8000"} // or some calculated value
215 print(server.url);
216 // => ...
217 </pre>
218
219 Now if everything seems breaky you can be 100% sure of what server you are connecting to.
220
221 </p>
222
223 <p>
224
225 If you have a variable that is dynamic but you still care about the value, you should do something like this:
226
b315102 @ianb deployment 786516a
authored
227 <pre class="test">
7ebac17 @ianb deployment 2b9f804
authored
228 var date = Date.now();
229 print(date == date, date);
230 // => true ...
231 </pre>
232
233 Think of this pattern of <code>print(x == y)</code> as a kind of <code>assertEqual()</code> equivalent.
234
235 </p>
236
237 </section>
238
239 <section id="async">
240 <header>
21c2592 @ianb deployment 436751e
authored
241 <h3 id="async">Testing async code</h3>
7ebac17 @ianb deployment 2b9f804
authored
242 </header>
243
244 <aside>
245 <p>For more on async and <code>wait</code> see <a href="reference.html#wait">the reference</a>.</p>
246 </aside>
247
248 <p>
249
250 This is all well and good, but lots of code in Javascript is <em>asynchronous</em>, meaning that you don't just call a function that returns a value. Doctest.js has an answer to that too: a great answer!
251
252 </p>
253
254 <p>
255
256 For our example we'll use <code>XMLHttpRequest</code>, a common source of asynchronosity. We'll test a request (just a loopback request, but if you are testing a foreign service you'd need <a href="http://enable-cors.org/">CORS access</a>). When we instantiate and setup the request we don't have anything really to test &mdash; we want to test what happens when the request <em>completes</em>.
257
258 </p>
259
260 <p>
261
23b8256 @ianb deployment b8b90e4
authored
262 To do this we'll use <code>wait()</code> &mdash; when this function is called the test runner will wait at the point where it sees <code>// =></code>, for a certain amount of time or until a certain condition is met. Only then will it compare all the output that has happened to what was expected, and run the next chunk of test.
7ebac17 @ianb deployment 2b9f804
authored
263
264 </p>
265
266 <p>
267
268 You can use this like: <code>wait(function () {return true when done})</code> or <code>wait(millisecondsToWait)</code>. We'll use the first form, which is almost always better, since it allows the test to continue more quickly. Tests also always time out eventually (by default the timeout is 5000 milliseconds, i.e., 5 seconds &mdash; by convention everything in Javascript is in milliseconds).
269
b315102 @ianb deployment 786516a
authored
270 <pre class="test">
7ebac17 @ianb deployment 2b9f804
authored
271 var endpoint = location.href;
272 print(endpoint);
273 // => ...
274
275 var req = new XMLHttpRequest();
276 req.open("GET", endpoint);
277 req.onreadystatechange = function () {
278 if (req.readyState != 4) {
279 // hasn't actually finished
280 return;
281 }
282 print("Result:", req.status, req.getResponseHeader('content-type'));
283 };
284 req.send();
285
286 wait(function () {return req.readyState == 4;});
287
288 print("Current state:", req.readyState);
289
290 /* =>
291 Current state: 1
292 Result: 200 text/html
293 */
294 </pre>
295
296 I put in something tricky there to try to clarify what <code>wait()</code> really does. You'll notice there's a call to <code>wait()</code> that makes sure that <code>req.readyState == 4</code> (that's the code that means the request is finished). But right after when we do <code>print(req.readyState)</code> it shows a readyState of 1. That's because the <em>entire</em> block is printed (from the previous <code>// =></code> output up until the next one). But the test runner keeps collecting output and doesn't run the next section until that <code>wait()</code> clause returns true.
297
298 </p>
299
300 <p>
301
302 Another thing to note is that <code>wait()</code> needs to be called when that block of code is run &mdash; it can't be inside a function that isn't called. That said, if you write test helper functions (and you should!), it often works well to put those calls in the helper function. We'll see an example of that next...
303
304 </p>
305
306 </section>
307
308 <section id="spy">
309 <header>
21c2592 @ianb deployment 436751e
authored
310 <h3 id="spy">The Spy</h3>
7ebac17 @ianb deployment 2b9f804
authored
311 </header>
312
313 <aside>
314 <p>For more information on <code>Spy</code> see <a href="reference.html#spy">the reference</a>.</p>
315 </aside>
316
317 <p>
318
319 Note: the next example will use some jQuery, just for the heck of it, though there is no special support for jQuery or other frameworks in Doctest.
320
321 </p>
322
323 <p>
324
325 If you use these tools you might end up writing code like this quite a lot:
326
b315102 @ianb deployment 786516a
authored
327 <pre class="test">
7ebac17 @ianb deployment 2b9f804
authored
328 // We've embedded a button just below this element
329 var button = $('#example-button');
330 // Just to highlight what we're working with:
331 button.css({border: '1px dotted #f00'});
332 button.click(function () {
333 print('Button clicked');
334 });
335
336 // Now we test that our event handler gets called when we do an artificial click of the button:
337 button.click();
338 // => Button clicked
339 </pre>
340
341 <button id="example-button" type="button">Example Button</button>
342
343 </p>
344
345 <p>
346
347 But maybe we are curious about the arguments passed to that handler &mdash; even though we ignored the arguments, there was one passed. And we might want to show what <code>this</code> is bound to; <code>this</code> is kind of like an invisible extra argument passed to every function invocation. We could make a fancier <code>print()</code> statement there. But instead, there's also a handy tool for tracking calls: <code>Spy</code>.
348
349 </p>
350
351 <p>
352
353 An example:
354
b315102 @ianb deployment 786516a
authored
355 <pre class="test">
7ebac17 @ianb deployment 2b9f804
authored
356 var button = $('#example-button2');
357 button.css({border: '1px dotted #00f'});
358 button.click(Spy('button.click'));
359 button.click();
360
361 // => ...
362 </pre>
363
364 <button id="example-button2" type="button">Example Button 2</button>
365
366 </p>
367
368 <p>
369
370 That's a lot more information! Let's break it down:
371
372 <pre>
373 <b style="color: #00a">&lt;button id="example-button2" style="border: 1px solid rgb(0, 0, 255); " type="button">Example Button 2&lt;/button>.</b><span style="color: #0a0">button.click</span>({ ...
374 </pre>
375
376 There's two bits of information here. The first is the value (in <span style="color: #00a">blue</span>) of <code>this</code>, which is the <code>#example-button2</code> element. You'll notice it shows the HTML of the element. If you want Spy to ignore this you can use <code>Spy('button.click', {ignoreThis: true})</code>.
377
378 </p>
379
380 <p>
381
382 The second value (in <span style="color: #0a0">green</span>) is the name we gave the Spy when we created it. Note that Spy names are also identifiers, that is, <code>Spy('button.click') === Spy('button.click')</code>.
383
384 </p>
385
386 <p>
387
388 Next of course is all the arguments. There's a lot of arguments there. They are... interesting. You'll notice some references to <code>...recursive...</code> which is what you get when you have self-referencing data structures. But maybe you want to test just a little of that structure without testing all of it. You might do something like this:
389
b315102 @ianb deployment 786516a
authored
390 <pre class="test">
7ebac17 @ianb deployment 2b9f804
authored
391 // Spy('button.click') fetches the same Spy we were using before, which still has all its call information
392 // .formatCall() shows the way the Spy was last called.
393 print(Spy('button.click').formatCall());
394
395 /* =>
396 &lt;button...&lt;/button>.button.click({
397 currentTarget: &lt;button...
398 ...
399 timeStamp: ?,
400 type: "click"
401 })
402 */
403
404 </pre>
405
406 So we've tested that the <code>type</code> is click, that it has a timeStamp (though not the value) and that the <code>currentTarget</code> is a button (presumably the button we bound it to). We still get to <em>see</em> all the other information, we just aren't <em>testing</em> it. This can be helpful in the future when you realize there's more you want to test &mdash; you can look at the test output and transcribe more into the test. Or when something fails later you might want to inspect that output to make sure everything is what you expect (and when you see something unexpected that's also a great time to expand your test).
407
408 </p>
409
410 <p>
411
412 Spies have a bunch of options, and act as a kind of mock object as well. You can pass in options as the second argument, like <code>Spy('name', {options...})</code>. Some highlights:
413
414
415 <dl>
416 <dt><code>applies</code></dt>
417 <dd>This is a function that the Spy "wraps". So if you do <code>Spy('click', {applies: function (event) {this.remove(); return false;}})</code> then you'll get the same output printed, but you'll also run <code>this.remove()</code>.</dd>
418
419 <dt><code>writes</code></dt>
420 <dd>If you set this to <code>false</code> then it won't automatically print out the calls. The values of the calls will still be recorded, and you can use <code>aSpy.formatCall()</code> to see them.</dd>
421
422 <dt><code>ignoreThis</code></dt>
423 <dd><p>Lots of code binds <code>this</code> without intending too. It's really easy in Javascript to do this. For instance, if you do <code>handlers[i]()</code> then <code>this</code> will be <code>handlers</code>. (Instead you might do <code>var handler = handlers[i]; handler()</code>)</p>
424
425 <p>Anyway, sometimes you don't care about <code>this</code>, and using <code>{ignoreThis: true}</code> lets you do that.
426 </p></dd>
427
428 <dt><code>returns</code></dt>
429 <dd>If you want the Spy to return a value when its called, give the value here. Normally it returns <code>undefined</code>.</dd>
430
431 <dt><code>throwError</code></dt>
432 <dd>This makes the Spy throw the given error anytime it is called.</dd>
433
434 <dt><code>wait</code></dt>
435 <dd>If you use <code>Spy('name', {wait: true})</code> then the test will wait until the Spy has been called. This is a pretty common pattern. It's basically the same as <code>Spy('name').wait()</code>.</dd>
436
437 </dl>
438
439 </p>
440
441 <p>
442
443 You can set values like <code>Spy.defaultOptions.writes = false</code> if you want to set one of these by default.
444
445 </p>
446
447 <p>
448
449 If you want to inspect how the Spy has been called, you can check a few attributes:
450
451 <dl>
452
453 <dt><code>.called</code></dt>
454 <dd>True once this Spy has been called.</dd>
455
456 <dt><code>.self</code> and <code>.selfList</code></dt>
457 <dd>This is the value of <code>this</code>, or <code>.selfList</code> contains a history for each call.</dd>
458
459 <dt><code>.args</code> and <code>.argList</code></dt>
460 <dd>The arguments the function was called with, or <code>.argList</code> is a history of arguments.</dd>
461
462 </dl>
463
464 </p>
465
466 </section>
467
468 <section id="console">
469 <header>
21c2592 @ianb deployment 436751e
authored
470 <h3 id="console-log">console.log</h3>
7ebac17 @ianb deployment 2b9f804
authored
471 </header>
472
473 <p>
474
475 This isn't a feature you have to <em>do</em> anything about, it's just there for you, so I'm just going to point it out.
476
477 </p>
478
479 <p>
480
481 When you use <code>console.log</code> (or any of its friends, like <code>console.warn</code>) those messages will be captured (in addition to going to the log as normal), and the output will be shown in the specific test where they happened. A quick example:
482
b315102 @ianb deployment 786516a
authored
483 <pre class="test">
7ebac17 @ianb deployment 2b9f804
authored
484 function enumProps(object) {
485 console.log('obj', object);
486 var result = {}
487 for (var attr in object) {
488 if (typeof object[attr] == "number" && attr.toUpperCase() == attr) {
489 result[object[attr]] = attr;
490 }
491 }
492 return result;
493 }
494
495 print(enumProps($('#example-button')[0]));
496
497 // => {...}
498
499 </pre>
500
501 You can think of it a little like <code>print()</code> goes to stdout, and <code>console.log()</code> goes to stderr.
502
503 </p>
504
505 </section>
506
507 <section id="abort">
508 <header>
21c2592 @ianb deployment 436751e
authored
509 <h3 id="abort">Giving Up</h3>
7ebac17 @ianb deployment 2b9f804
authored
510 </header>
511
512 <p>
513
514 Tests often require some feature or setup to be usable at all. When it's not setup right you'll just get a bunch of meaningless failures. For this reason there's a way to abort all your tests. If you call <code>Abort()</code> then no further tests will be run. If you want to connect to a server, for instance, you might check that the server is really there, and if not then just abort the rest of the tests. For example:
515
516 <pre>
517 $.ajax({
518 url: '/ping',
519 success: Spy('ping', {wait: true, ignoreThis: true}),
520 error: function () {
521 Abort("Server isn't up");
522 }
523 });
524
525 // => ping(...)
526 </pre>
527
528 </p>
529
530 </section>
531
532 <section id="html">
533 <header>
21c2592 @ianb deployment 436751e
authored
534 <h2 id="html">Setting Up Your HTML</h2>
7ebac17 @ianb deployment 2b9f804
authored
535 </header>
536
537 <aside>
538 <p>For more on the HTML setup see <a href="reference.html#format">the reference documentation</a>.</p>
539 </aside>
540
541 <p>
542
543 I wanted to show you all the cool features of doctest first, but you can't actually use any of them unless you set up a test runner page. Luckily the page is pretty simple. Let's say you've put doctest.js into <code>doctest/</code>:
544
545 <pre>
546 &lt;DOCTYPE html>
547 &lt;html>
548 &lt;head>
549 &lt;meta charset="UTF-8">
550 &lt;title>My Test&lt;/title>
551 &lt;script src="doctest/doctest.js">&lt;/script>
552 &lt;link href="doctest/doctest.css" rel="stylesheet">
553 <b>&lt;script src="mylibrary.js">&lt;/script></b>
554 &lt;/head>
555 &lt;body class="autodoctest">
556
557 A test:
558
b315102 @ianb deployment 786516a
authored
559 &lt;pre class="test">
7ebac17 @ianb deployment 2b9f804
authored
560 test goes here
561 &lt;/pre>
562
563 &lt;/body>&lt;/html>
564 </pre>
565
566 </p>
567
568 <p>
569
570 Mostly it's just boilerplate: you have to include <code>doctest.js</code> and <code>doctest.css</code> and of course any libraries or dependencies of the thing you are testing. You also must use <b><code>&lt;body class="autodoctest"></code></b> &mdash; that's what tells doctest.js you want to find and run tests right away.
571
572 </p>
573
574 <p>
575
b315102 @ianb deployment 786516a
authored
576 Each test then is in a <code>&lt;pre class="test"></code>. You might not want to actully write your tests <em>inside</em> the HTML, and instead put them in a separate Javascript file. To do that use:
7ebac17 @ianb deployment 2b9f804
authored
577
578 <pre>
b315102 @ianb deployment 786516a
authored
579 &lt;pre class="test" href="./my_tests.js">&lt;/pre>
7ebac17 @ianb deployment 2b9f804
authored
580 </pre>
581
582 This will load the test code from <code>./my_tests.js</code> and inline it into the element. This is how I personally write most of my tests, though when moving between a narrative and tests (as I am doing in this tutorial) it is nice to keep the tests together with the descriptions.
583
584 </p>
585
586 <p>
587
23b8256 @ianb deployment b8b90e4
authored
588 Note that specifically when you use <code>href="URL.js"</code> you can split the tests into sections by including the comment <code><b>// == SECTION</b> Your Section Header Name</code> in the included file, and you'll get multiple elements with headers automatically.
7ebac17 @ianb deployment 2b9f804
authored
589
590 </p>
591
592 <p>
593
594 A pass/fail summary is automatically added to the top of the page, though you can use <code>&lt;div id="doctest-output">&lt;/div></code> to position it someplace specific (as we did in this tutorial).
595
596 </p>
597
598 </section>
599
734197c @ianb deployment c824fca
authored
600
601 <section id="feedback">
602 <header>
21c2592 @ianb deployment 436751e
authored
603 <h2 id="feedback">Feedback?</h2>
734197c @ianb deployment c824fca
authored
604 </header>
605
606 <p>Was something in this tutorial confusing? Is there a testing problem or pattern you think this tutorial should talk about? Please give feedback in the form of an <a href="https://github.com/ianb/doctestjs/issues/new">new issue</a>. Thanks!</p>
607
608 </section>
609
610
611 <h3 href="try.html">Live Demo...</h3>
612
7ebac17 @ianb deployment 2b9f804
authored
613 </article>
614
615 <!--
616 <aside>
617 <h3>aside</h3>
618
619 <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam sodales urna non odio egestas tempor. Nunc vel vehicula ante. Etiam bibendum iaculis libero, eget molestie nisl pharetra in. In semper consequat est, eu porta velit mollis nec. Curabitur posuere enim eget turpis feugiat tempor. Etiam ullamcorper lorem dapibus velit suscipit ultrices.</p>
620
621 </aside>
622 -->
623
624 <!-- /BODY -->
625
626 </div> <!-- #main -->
627
628 </div> <!-- #main-container -->
629
630 <div class="footer-container">
631 <footer class="wrapper">
734197c @ianb deployment c824fca
authored
632 <h3 class="no-toc">doctest.js is by <a href="http://ianbicking.org">Ian Bicking</a>.
7ebac17 @ianb deployment 2b9f804
authored
633 It's on <a href="https://github.com/ianb/doctestjs">github</a>!</h3>
634 </footer>
635 </div>
636
637 <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
638 <script>
639 window.jQuery || document.write('<script src="resources/boilerplate/js/vendor/jquery-1.8.1.min.js"><\/script>')
640 </script>
641
642 <script src="resources/boilerplate/js/main.js"></script>
643
644 <script type="text/javascript">
645
646 var _gaq = _gaq || [];
647 _gaq.push(['_setAccount', 'UA-34921728-1']);
648 _gaq.push(['_trackPageview']);
649
650 (function() {
651 var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
652 ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
653 var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
654 })();
655
656 </script>
657
658 </body>
659 </html>
Something went wrong with that request. Please try again.