ruby-contract 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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>