ruby-contract 0.1.1

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 (74) hide show
  1. data/COPYING +56 -0
  2. data/Manifest +85 -0
  3. data/README +32 -0
  4. data/TODO +83 -0
  5. data/doc/classes/Contract.html +599 -0
  6. data/doc/classes/Contract/Check.html +229 -0
  7. data/doc/classes/Contract/Check/All.html +172 -0
  8. data/doc/classes/Contract/Check/Any.html +172 -0
  9. data/doc/classes/Contract/Check/Block.html +172 -0
  10. data/doc/classes/Contract/Check/None.html +173 -0
  11. data/doc/classes/Contract/Check/Quack.html +172 -0
  12. data/doc/classes/Contract/ContractError.html +151 -0
  13. data/doc/classes/Contract/ContractException.html +162 -0
  14. data/doc/classes/Contract/ContractMismatch.html +134 -0
  15. data/doc/classes/Kernel.html +256 -0
  16. data/doc/classes/Method.html +135 -0
  17. data/doc/classes/MethodSignatureMixin.html +208 -0
  18. data/doc/classes/Module.html +526 -0
  19. data/doc/created.rid +1 -0
  20. data/doc/dot/f_0.dot +14 -0
  21. data/doc/dot/f_0.png +0 -0
  22. data/doc/dot/f_1.dot +14 -0
  23. data/doc/dot/f_1.png +0 -0
  24. data/doc/dot/f_2.dot +14 -0
  25. data/doc/dot/f_2.png +0 -0
  26. data/doc/dot/f_3.dot +112 -0
  27. data/doc/dot/f_3.png +0 -0
  28. data/doc/dot/f_4.dot +62 -0
  29. data/doc/dot/f_4.png +0 -0
  30. data/doc/dot/f_5.dot +62 -0
  31. data/doc/dot/f_5.png +0 -0
  32. data/doc/dot/f_6.dot +224 -0
  33. data/doc/dot/f_6.png +0 -0
  34. data/doc/dot/f_6_0.dot +24 -0
  35. data/doc/dot/f_6_0.png +0 -0
  36. data/doc/dot/f_6_1.dot +24 -0
  37. data/doc/dot/f_6_1.png +0 -0
  38. data/doc/dot/f_7.dot +62 -0
  39. data/doc/dot/f_7.png +0 -0
  40. data/doc/files/COPYING.html +168 -0
  41. data/doc/files/README.html +146 -0
  42. data/doc/files/TODO.html +240 -0
  43. data/doc/files/lib/contract/assertions_rb.html +118 -0
  44. data/doc/files/lib/contract/exception_rb.html +125 -0
  45. data/doc/files/lib/contract/integration_rb.html +130 -0
  46. data/doc/files/lib/contract/overrides_rb.html +118 -0
  47. data/doc/files/lib/contract_rb.html +127 -0
  48. data/doc/fr_class_index.html +40 -0
  49. data/doc/fr_file_index.html +34 -0
  50. data/doc/fr_method_index.html +45 -0
  51. data/doc/index.html +24 -0
  52. data/doc/rdoc-style.css +208 -0
  53. data/lib/contract.rb +146 -0
  54. data/lib/contract/assertions.rb +42 -0
  55. data/lib/contract/exception.rb +95 -0
  56. data/lib/contract/integration.rb +664 -0
  57. data/lib/contract/overrides.rb +41 -0
  58. data/setup.rb +1360 -0
  59. data/test/coverage/_-lib-contract-assertions_rb.html +526 -0
  60. data/test/coverage/_-lib-contract-exception_rb.html +632 -0
  61. data/test/coverage/_-lib-contract-integration_rb.html +1450 -0
  62. data/test/coverage/_-lib-contract-overrides_rb.html +524 -0
  63. data/test/coverage/_-lib-contract_rb.html +724 -0
  64. data/test/coverage/__-lib-contract-assertions_rb.html +484 -0
  65. data/test/coverage/__-lib-contract-exception_rb.html +537 -0
  66. data/test/coverage/__-lib-contract-integration_rb.html +946 -0
  67. data/test/coverage/__-lib-contract-overrides_rb.html +483 -0
  68. data/test/coverage/__-lib-contract_rb.html +583 -0
  69. data/test/coverage/index.html +93 -0
  70. data/test/tc_all.rb +8 -0
  71. data/test/tc_contract.rb +109 -0
  72. data/test/tc_exception.rb +43 -0
  73. data/test/tc_integration.rb +357 -0
  74. metadata +136 -0
@@ -0,0 +1,583 @@
1
+ <?xml version="1.0" encoding="ISO-8859-15"?>
2
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
3
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
4
+ <html xmlns="http://www.w3.org/1999/xhtml">
5
+ <head><title>../lib/contract.rb - coverage</title>
6
+ <style type="text/css">body {
7
+ background-color: rgb(180, 180, 180);
8
+ }
9
+ span.marked {
10
+ background-color: rgb(185, 200, 200);
11
+ display: block;
12
+ }
13
+ span.inferred {
14
+ background-color: rgb(180, 195, 195);
15
+ display: block;
16
+ }
17
+ span.run0 {
18
+ background-color: rgb(178, 204, 255);
19
+ display: block;
20
+ }
21
+ span.run1 {
22
+ background-color: rgb(178, 206, 255);
23
+ display: block;
24
+ }
25
+ span.run2 {
26
+ background-color: rgb(178, 209, 255);
27
+ display: block;
28
+ }
29
+ span.run3 {
30
+ background-color: rgb(178, 211, 255);
31
+ display: block;
32
+ }
33
+ span.run4 {
34
+ background-color: rgb(178, 214, 255);
35
+ display: block;
36
+ }
37
+ span.run5 {
38
+ background-color: rgb(178, 218, 255);
39
+ display: block;
40
+ }
41
+ span.run6 {
42
+ background-color: rgb(178, 220, 255);
43
+ display: block;
44
+ }
45
+ span.run7 {
46
+ background-color: rgb(178, 223, 255);
47
+ display: block;
48
+ }
49
+ span.run8 {
50
+ background-color: rgb(178, 225, 255);
51
+ display: block;
52
+ }
53
+ span.run9 {
54
+ background-color: rgb(178, 228, 255);
55
+ display: block;
56
+ }
57
+ span.run10 {
58
+ background-color: rgb(178, 232, 255);
59
+ display: block;
60
+ }
61
+ span.run11 {
62
+ background-color: rgb(178, 234, 255);
63
+ display: block;
64
+ }
65
+ span.run12 {
66
+ background-color: rgb(178, 237, 255);
67
+ display: block;
68
+ }
69
+ span.run13 {
70
+ background-color: rgb(178, 239, 255);
71
+ display: block;
72
+ }
73
+ span.run14 {
74
+ background-color: rgb(178, 242, 255);
75
+ display: block;
76
+ }
77
+ span.run15 {
78
+ background-color: rgb(178, 246, 255);
79
+ display: block;
80
+ }
81
+ span.run16 {
82
+ background-color: rgb(178, 248, 255);
83
+ display: block;
84
+ }
85
+ span.run17 {
86
+ background-color: rgb(178, 251, 255);
87
+ display: block;
88
+ }
89
+ span.run18 {
90
+ background-color: rgb(178, 253, 255);
91
+ display: block;
92
+ }
93
+ span.run19 {
94
+ background-color: rgb(178, 255, 253);
95
+ display: block;
96
+ }
97
+ span.run20 {
98
+ background-color: rgb(178, 255, 249);
99
+ display: block;
100
+ }
101
+ span.run21 {
102
+ background-color: rgb(178, 255, 247);
103
+ display: block;
104
+ }
105
+ span.run22 {
106
+ background-color: rgb(178, 255, 244);
107
+ display: block;
108
+ }
109
+ span.run23 {
110
+ background-color: rgb(178, 255, 242);
111
+ display: block;
112
+ }
113
+ span.run24 {
114
+ background-color: rgb(178, 255, 239);
115
+ display: block;
116
+ }
117
+ span.run25 {
118
+ background-color: rgb(178, 255, 235);
119
+ display: block;
120
+ }
121
+ span.run26 {
122
+ background-color: rgb(178, 255, 233);
123
+ display: block;
124
+ }
125
+ span.run27 {
126
+ background-color: rgb(178, 255, 230);
127
+ display: block;
128
+ }
129
+ span.run28 {
130
+ background-color: rgb(178, 255, 228);
131
+ display: block;
132
+ }
133
+ span.run29 {
134
+ background-color: rgb(178, 255, 225);
135
+ display: block;
136
+ }
137
+ span.run30 {
138
+ background-color: rgb(178, 255, 221);
139
+ display: block;
140
+ }
141
+ span.run31 {
142
+ background-color: rgb(178, 255, 219);
143
+ display: block;
144
+ }
145
+ span.run32 {
146
+ background-color: rgb(178, 255, 216);
147
+ display: block;
148
+ }
149
+ span.run33 {
150
+ background-color: rgb(178, 255, 214);
151
+ display: block;
152
+ }
153
+ span.run34 {
154
+ background-color: rgb(178, 255, 211);
155
+ display: block;
156
+ }
157
+ span.run35 {
158
+ background-color: rgb(178, 255, 207);
159
+ display: block;
160
+ }
161
+ span.run36 {
162
+ background-color: rgb(178, 255, 205);
163
+ display: block;
164
+ }
165
+ span.run37 {
166
+ background-color: rgb(178, 255, 202);
167
+ display: block;
168
+ }
169
+ span.run38 {
170
+ background-color: rgb(178, 255, 200);
171
+ display: block;
172
+ }
173
+ span.run39 {
174
+ background-color: rgb(178, 255, 197);
175
+ display: block;
176
+ }
177
+ span.run40 {
178
+ background-color: rgb(178, 255, 193);
179
+ display: block;
180
+ }
181
+ span.run41 {
182
+ background-color: rgb(178, 255, 191);
183
+ display: block;
184
+ }
185
+ span.run42 {
186
+ background-color: rgb(178, 255, 188);
187
+ display: block;
188
+ }
189
+ span.run43 {
190
+ background-color: rgb(178, 255, 186);
191
+ display: block;
192
+ }
193
+ span.run44 {
194
+ background-color: rgb(178, 255, 183);
195
+ display: block;
196
+ }
197
+ span.run45 {
198
+ background-color: rgb(178, 255, 179);
199
+ display: block;
200
+ }
201
+ span.run46 {
202
+ background-color: rgb(179, 255, 178);
203
+ display: block;
204
+ }
205
+ span.run47 {
206
+ background-color: rgb(182, 255, 178);
207
+ display: block;
208
+ }
209
+ span.run48 {
210
+ background-color: rgb(184, 255, 178);
211
+ display: block;
212
+ }
213
+ span.run49 {
214
+ background-color: rgb(187, 255, 178);
215
+ display: block;
216
+ }
217
+ span.run50 {
218
+ background-color: rgb(191, 255, 178);
219
+ display: block;
220
+ }
221
+ span.run51 {
222
+ background-color: rgb(193, 255, 178);
223
+ display: block;
224
+ }
225
+ span.run52 {
226
+ background-color: rgb(196, 255, 178);
227
+ display: block;
228
+ }
229
+ span.run53 {
230
+ background-color: rgb(198, 255, 178);
231
+ display: block;
232
+ }
233
+ span.run54 {
234
+ background-color: rgb(201, 255, 178);
235
+ display: block;
236
+ }
237
+ span.run55 {
238
+ background-color: rgb(205, 255, 178);
239
+ display: block;
240
+ }
241
+ span.run56 {
242
+ background-color: rgb(207, 255, 178);
243
+ display: block;
244
+ }
245
+ span.run57 {
246
+ background-color: rgb(210, 255, 178);
247
+ display: block;
248
+ }
249
+ span.run58 {
250
+ background-color: rgb(212, 255, 178);
251
+ display: block;
252
+ }
253
+ span.run59 {
254
+ background-color: rgb(215, 255, 178);
255
+ display: block;
256
+ }
257
+ span.run60 {
258
+ background-color: rgb(219, 255, 178);
259
+ display: block;
260
+ }
261
+ span.run61 {
262
+ background-color: rgb(221, 255, 178);
263
+ display: block;
264
+ }
265
+ span.run62 {
266
+ background-color: rgb(224, 255, 178);
267
+ display: block;
268
+ }
269
+ span.run63 {
270
+ background-color: rgb(226, 255, 178);
271
+ display: block;
272
+ }
273
+ span.run64 {
274
+ background-color: rgb(229, 255, 178);
275
+ display: block;
276
+ }
277
+ span.run65 {
278
+ background-color: rgb(233, 255, 178);
279
+ display: block;
280
+ }
281
+ span.run66 {
282
+ background-color: rgb(235, 255, 178);
283
+ display: block;
284
+ }
285
+ span.run67 {
286
+ background-color: rgb(238, 255, 178);
287
+ display: block;
288
+ }
289
+ span.run68 {
290
+ background-color: rgb(240, 255, 178);
291
+ display: block;
292
+ }
293
+ span.run69 {
294
+ background-color: rgb(243, 255, 178);
295
+ display: block;
296
+ }
297
+ span.run70 {
298
+ background-color: rgb(247, 255, 178);
299
+ display: block;
300
+ }
301
+ span.run71 {
302
+ background-color: rgb(249, 255, 178);
303
+ display: block;
304
+ }
305
+ span.run72 {
306
+ background-color: rgb(252, 255, 178);
307
+ display: block;
308
+ }
309
+ span.run73 {
310
+ background-color: rgb(255, 255, 178);
311
+ display: block;
312
+ }
313
+ span.run74 {
314
+ background-color: rgb(255, 252, 178);
315
+ display: block;
316
+ }
317
+ span.run75 {
318
+ background-color: rgb(255, 248, 178);
319
+ display: block;
320
+ }
321
+ span.run76 {
322
+ background-color: rgb(255, 246, 178);
323
+ display: block;
324
+ }
325
+ span.run77 {
326
+ background-color: rgb(255, 243, 178);
327
+ display: block;
328
+ }
329
+ span.run78 {
330
+ background-color: rgb(255, 240, 178);
331
+ display: block;
332
+ }
333
+ span.run79 {
334
+ background-color: rgb(255, 238, 178);
335
+ display: block;
336
+ }
337
+ span.run80 {
338
+ background-color: rgb(255, 234, 178);
339
+ display: block;
340
+ }
341
+ span.run81 {
342
+ background-color: rgb(255, 232, 178);
343
+ display: block;
344
+ }
345
+ span.run82 {
346
+ background-color: rgb(255, 229, 178);
347
+ display: block;
348
+ }
349
+ span.run83 {
350
+ background-color: rgb(255, 226, 178);
351
+ display: block;
352
+ }
353
+ span.run84 {
354
+ background-color: rgb(255, 224, 178);
355
+ display: block;
356
+ }
357
+ span.run85 {
358
+ background-color: rgb(255, 220, 178);
359
+ display: block;
360
+ }
361
+ span.run86 {
362
+ background-color: rgb(255, 218, 178);
363
+ display: block;
364
+ }
365
+ span.run87 {
366
+ background-color: rgb(255, 215, 178);
367
+ display: block;
368
+ }
369
+ span.run88 {
370
+ background-color: rgb(255, 212, 178);
371
+ display: block;
372
+ }
373
+ span.run89 {
374
+ background-color: rgb(255, 210, 178);
375
+ display: block;
376
+ }
377
+ span.run90 {
378
+ background-color: rgb(255, 206, 178);
379
+ display: block;
380
+ }
381
+ span.run91 {
382
+ background-color: rgb(255, 204, 178);
383
+ display: block;
384
+ }
385
+ span.run92 {
386
+ background-color: rgb(255, 201, 178);
387
+ display: block;
388
+ }
389
+ span.run93 {
390
+ background-color: rgb(255, 198, 178);
391
+ display: block;
392
+ }
393
+ span.run94 {
394
+ background-color: rgb(255, 196, 178);
395
+ display: block;
396
+ }
397
+ span.run95 {
398
+ background-color: rgb(255, 192, 178);
399
+ display: block;
400
+ }
401
+ span.run96 {
402
+ background-color: rgb(255, 189, 178);
403
+ display: block;
404
+ }
405
+ span.run97 {
406
+ background-color: rgb(255, 187, 178);
407
+ display: block;
408
+ }
409
+ span.run98 {
410
+ background-color: rgb(255, 184, 178);
411
+ display: block;
412
+ }
413
+ span.run99 {
414
+ background-color: rgb(255, 182, 178);
415
+ display: block;
416
+ }
417
+
418
+ div.overview {
419
+ border-bottom: 8px solid black;
420
+ }
421
+ </style></head>
422
+ <body><div class="overview">
423
+ <table>
424
+ <tr><td>filename</td><td><tt>../lib/contract.rb</tt></td></tr>
425
+ <tr><td>total coverage</td><td>97.9</td></tr>
426
+ <tr><td>code coverage</td><td>95.1</td></tr>
427
+ </table>
428
+ </div>
429
+ <pre><span class="inferred"> 1 # Contains the main implementation of the Contract class.
430
+ 2 # :main:Contract
431
+ 3
432
+ </span><span class="marked"> 4 require 'test/unit/testcase'
433
+ 5 require 'test/unit/testresult'
434
+ 6 require 'test/unit/testsuite'
435
+ </span><span class="inferred"> 7
436
+ </span><span class="marked"> 8 require 'contract/exception'
437
+ 9 require 'contract/overrides'
438
+ 10 require 'contract/assertions'
439
+ 11 require 'contract/integration'
440
+ </span><span class="inferred"> 12
441
+ 13 # Represents a contract between Objects as a collection of test cases.
442
+ 14 # Objects are said to fulfill a contract if all test cases suceed. This
443
+ 15 # is useful for ensuring that Objects your code is getting behave in a
444
+ 16 # way that you expect them to behave so you can fail early or execute
445
+ 17 # different logic for Objects with different interfaces.
446
+ 18 #
447
+ 19 # The tests of the test suite will be run on a copy of the tested Object
448
+ 20 # so you can safely test its behavior without having to fear data loss.
449
+ 21 # By default Contracts obtain deep copies of Objects by serializing and
450
+ 22 # unserializing them with Ruby's +Marshal+ functionality. This will work
451
+ 23 # in most cases but can fail for Objects containing unserializable parts
452
+ 24 # like Procs, Files or Sockets. In those cases it is currently of your
453
+ 25 # responsibility to provide a fitting implementation by overwriting the
454
+ 26 # Contract.deep_copy method. In the future the contract library might
455
+ 27 # provide different implementations of it via Ruby's mixin mechanism.
456
+ </span><span class="marked"> 28 class Contract &lt; Test::Unit::TestCase
457
+ 29 id = %q$Id: contract.rb 86 2005-02-02 20:58:46Z flgr $
458
+ </span><span class="inferred"> 30 # The Version of the contract library you are using.
459
+ </span><span class="marked"> 31 Version = id.split(&quot; &quot;)[2].to_i
460
+ </span><span class="inferred"> 32
461
+ 33 # Returns true if the given object fulfills this contract.
462
+ 34 # This is useful for implementing dispatching mechanisms where you
463
+ 35 # want to hit different code branches based on whether an Object has
464
+ 36 # one or another interface.
465
+ </span><span class="marked"> 37 def self.fulfilled_by?(object)
466
+ 38 self.test(object).nil?
467
+ </span><span class="inferred"> 39 end
468
+ 40
469
+ </span><span class="marked"> 41 class &lt;&lt; self
470
+ </span><span class="inferred"> 42 # You can use contracts in +case+ ... +when+ statements or in
471
+ 43 # Module#signature checks. For example:
472
+ 44 # case obj
473
+ 45 # when Numeric then obj + 1
474
+ 46 # when ListContract then obj + [1]
475
+ 47 # end
476
+ </span><span class="marked"> 48 alias :=== :fulfilled_by?
477
+ </span><span class="inferred"> 49 end
478
+ 50
479
+ 51 # Enforces that object implements this contract. If it does not an
480
+ 52 # Exception will be raised. This is useful for example useful when you
481
+ 53 # need to ensure that the arguments given to a method fulfill a given
482
+ 54 # contract.
483
+ 55 #
484
+ 56 # Note that using Module#enforce is a higher-level way of checking
485
+ 57 # arguments and return values for the conformance of a given type. You
486
+ 58 # might however still want to use Contract.enforce directly when you
487
+ 59 # need more flexibility.
488
+ </span><span class="marked"> 60 def self.enforce(object)
489
+ 61 reason = self.test(object)
490
+ 62 raise reason if reason
491
+ </span><span class="inferred"> 63 end
492
+ 64
493
+ 65 # Tests whether the given Object fulfils this contract.
494
+ 66 #
495
+ 67 # Note: This will return the first reason for the Object not fulfilling
496
+ 68 # the contract or +nil+ in case it fulfills it.
497
+ </span><span class="marked"> 69 def self.test(object, return_all = false)
498
+ 70 reasons = []
499
+ </span><span class="inferred"> 71
500
+ </span><span class="marked"> 72 result = Test::Unit::TestResult.new
501
+ 73 result.add_listener(Test::Unit::TestResult::FAULT) do |fault|
502
+ 74 reason = Contract.fault_to_exception(fault, object, self)
503
+ 75 return reason unless return_all
504
+ 76 reasons &lt;&lt; reason
505
+ </span><span class="inferred"> 77 end
506
+ 78
507
+ </span><span class="marked"> 79 self.suite.run(result, deep_copy(object))
508
+ </span><span class="inferred"> 80
509
+ </span><span class="marked"> 81 return reasons unless result.passed?
510
+ </span><span class="inferred"> 82 end
511
+ 83
512
+ 84 # Same as Contract.test, but will return all reasons for the Object not
513
+ 85 # fulfilling the contract in an Array or nil in case of fulfillment.
514
+ 86 # (as an Array of Exceptions) or +nil+ in the case it does fulfill it.
515
+ </span><span class="marked"> 87 def self.test_all(object)
516
+ 88 test(object, true)
517
+ </span><span class="inferred"> 89 end
518
+ 90
519
+ 91 # This method is used internally for getting a copy of Objects that
520
+ 92 # the contract is checked against. By default it uses Ruby's +Marshal+
521
+ 93 # functionality for obtaining a copy, but this can fail if the Object
522
+ 94 # contains unserializable parts like Procs, Files or Sockets. It is
523
+ 95 # currently your responsibility to provide a fitting implementation
524
+ 96 # of this by overwriting the method in case the default implementation
525
+ 97 # does not work for you. In the future the contract library might offer
526
+ 98 # different implementations for this via Ruby's mixin mechanism.
527
+ </span><span class="marked"> 99 def self.deep_copy(object)
528
+ 100 Marshal.load(Marshal.dump(object))
529
+ </span><span class="inferred">101 end
530
+ 102
531
+ 103 # Fulfilling this Contract (via Module#fulfills) implies that the Object
532
+ 104 # is automatically compatible with the specified mixins which will then
533
+ 105 # be included automatically. For example the Enumerable relationship
534
+ 106 # could be expressed like this:
535
+ 107 #
536
+ 108 # class EnumerableContract &lt; Contract
537
+ 109 # provides :each
538
+ 110 # implies Enumerable
539
+ 111 # end
540
+ </span><span class="marked">112 def self.implies(*mixins)
541
+ 113 mixins.each do |mixin|
542
+ 114 if not mixin.is_a?(Module) then
543
+ 115 raise(TypeError, &quot;wrong argument type #{mixin.class} for &quot; +
544
+ </span><span class="inferred">116 &quot;#{mixin.inspect} (expected Module)&quot;)
545
+ 117 end
546
+ 118 end
547
+ 119
548
+ </span><span class="marked">120 @implications ||= Array.new
549
+ 121 @implications += mixins
550
+ </span><span class="inferred">122 end
551
+ 123
552
+ </span><span class="marked">124 class &lt;&lt; self
553
+ </span><span class="inferred">125 # Returns all implications of a given contract that were stated via
554
+ 126 # calling Contract.implies.
555
+ </span><span class="marked">127 attr_reader :implications
556
+ </span><span class="inferred">128 end
557
+ 129
558
+ </span><span class="marked">130 def self.implications() # :nodoc:
559
+ 131 @implications ||= Array.new
560
+ </span><span class="inferred">132
561
+ </span><span class="marked">133 ancestors[1 .. -1].inject(@implications) do |result, ancestor|
562
+ 134 if ancestor.respond_to?(:implications) then
563
+ 135 ancestor.implications + result
564
+ </span><span class="inferred">136 else
565
+ </span><span class="marked">137 result
566
+ </span><span class="inferred">138 end
567
+ </span><span class="false">139 end.uniq
568
+ 140 end
569
+ 141 end
570
+ </span></pre>
571
+ <hr />
572
+ <p>
573
+ <a href="http://validator.w3.org/check/referer">
574
+ <img src="http://www.w3.org/Icons/valid-xhtml11"
575
+ alt="Valid XHTML 1.1!" height="31" width="88" />
576
+ </a>
577
+ <a href="http://jigsaw.w3.org/css-validator/">
578
+ <img style="border:0;width:88px;height:31px"
579
+ src="http://jigsaw.w3.org/css-validator/images/vcss"
580
+ alt="Valid CSS!" />
581
+ </a>
582
+ </p>
583
+ </body></html>