| [12] | 1 | <html> |
|---|
| 2 | |
|---|
| 3 | <head> |
|---|
| 4 | <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> |
|---|
| 5 | |
|---|
| 6 | <title>Boost Random Number Library Concepts</title> |
|---|
| 7 | </head> |
|---|
| 8 | |
|---|
| 9 | <body bgcolor="#FFFFFF" text="#000000"> |
|---|
| 10 | |
|---|
| 11 | <h1>Random Number Generator Library Concepts</h1> |
|---|
| 12 | |
|---|
| 13 | |
|---|
| 14 | <h2>Introduction</h2> |
|---|
| 15 | |
|---|
| 16 | Random numbers are required in a number of different problem domains, |
|---|
| 17 | such as |
|---|
| 18 | <ul> |
|---|
| 19 | <li>numerics (simulation, Monte-Carlo integration) |
|---|
| 20 | <li>games (non-deterministic enemy behavior) |
|---|
| 21 | <li>security (key generation) |
|---|
| 22 | <li>testing (random coverage in white-box tests) |
|---|
| 23 | </ul> |
|---|
| 24 | |
|---|
| 25 | The Boost Random Number Generator Library provides a framework |
|---|
| 26 | for random number generators with well-defined properties so that the |
|---|
| 27 | generators can be used in the demanding numerics and security domains. |
|---|
| 28 | |
|---|
| 29 | For a general introduction to random numbers in numerics, see |
|---|
| 30 | <blockquote> |
|---|
| 31 | "Numerical Recipes in C: The art of scientific computing", William |
|---|
| 32 | H. Press, Saul A. Teukolsky, William A. Vetterling, Brian P. Flannery, |
|---|
| 33 | 2nd ed., 1992, pp. 274-328 |
|---|
| 34 | </blockquote> |
|---|
| 35 | |
|---|
| 36 | Depending on the requirements of the problem domain, different |
|---|
| 37 | variations of random number generators are appropriate: |
|---|
| 38 | |
|---|
| 39 | <ul> |
|---|
| 40 | <li>non-deterministic random number generator |
|---|
| 41 | <li>pseudo-random number generator |
|---|
| 42 | <li>quasi-random number generator |
|---|
| 43 | </ul> |
|---|
| 44 | |
|---|
| 45 | All variations have some properties in common, these concepts (in the |
|---|
| 46 | STL sense) are called NumberGenerator and |
|---|
| 47 | UniformRandomNumberGenerator. Each concept will be defined in a |
|---|
| 48 | subsequent section. |
|---|
| 49 | |
|---|
| 50 | <p> |
|---|
| 51 | |
|---|
| 52 | The goals for this library are the following: |
|---|
| 53 | <ul> |
|---|
| 54 | <li>allow easy integration of third-party random-number generators |
|---|
| 55 | <li>define a validation interface for the generators |
|---|
| 56 | <li>provide easy-to-use front-end classes which model popular |
|---|
| 57 | distributions |
|---|
| 58 | <li>provide maximum efficiency |
|---|
| 59 | <li>allow control on quantization effects in front-end processing |
|---|
| 60 | (not yet done) |
|---|
| 61 | </ul> |
|---|
| 62 | |
|---|
| 63 | |
|---|
| 64 | <h2><a name="number_generator">Number Generator</a></h2> |
|---|
| 65 | |
|---|
| 66 | A number generator is a <em>function object</em> (std:20.3 |
|---|
| 67 | [lib.function.objects]) that takes zero arguments. Each call to |
|---|
| 68 | <code>operator()</code> returns a number. |
|---|
| 69 | |
|---|
| 70 | |
|---|
| 71 | In the following table, <code>X</code> denotes a number generator |
|---|
| 72 | class returning objects of type <code>T</code>, and <code>u</code> is |
|---|
| 73 | a value of <code>X</code>. |
|---|
| 74 | |
|---|
| 75 | <p> |
|---|
| 76 | |
|---|
| 77 | <table border=1> |
|---|
| 78 | <tr><th colspan=3 align=center><code>NumberGenerator</code> |
|---|
| 79 | requirements</th></tr> |
|---|
| 80 | <tr><td>expression</td><td>return type</td> |
|---|
| 81 | <td>pre/post-condition</td></tr> |
|---|
| 82 | <tr><td><code>X::result_type</code></td><td>T</td> |
|---|
| 83 | <td><code>std::numeric_limits<T>::is_specialized</code> is true, |
|---|
| 84 | <code>T</code> is <code>LessThanComparable</code></td></tr> |
|---|
| 85 | <tr><td><code>u.operator()()</code></td><td>T</td><td>-</td></tr> |
|---|
| 86 | </table> |
|---|
| 87 | |
|---|
| 88 | <p> |
|---|
| 89 | |
|---|
| 90 | <em>Note:</em> The NumberGenerator requirements do not impose any |
|---|
| 91 | restrictions on the characteristics of the returned numbers. |
|---|
| 92 | |
|---|
| 93 | |
|---|
| 94 | <h2><a name="uniform-rng">Uniform Random Number Generator</a></h2> |
|---|
| 95 | |
|---|
| 96 | A uniform random number generator is a NumberGenerator that provides a |
|---|
| 97 | sequence of random numbers uniformly distributed on a given range. |
|---|
| 98 | The range can be compile-time fixed or available (only) after run-time |
|---|
| 99 | construction of the object. |
|---|
| 100 | |
|---|
| 101 | <p> |
|---|
| 102 | The <em>tight lower bound</em> of some (finite) set S is the (unique) |
|---|
| 103 | member l in S, so that for all v in S, l <= v holds. Likewise, the |
|---|
| 104 | <em>tight upper bound</em> of some (finite) set S is the (unique) |
|---|
| 105 | member u in S, so that for all v in S, v <= u holds. |
|---|
| 106 | |
|---|
| 107 | <p> |
|---|
| 108 | In the following table, <code>X</code> denotes a number generator |
|---|
| 109 | class returning objects of type <code>T</code>, and <code>v</code> is |
|---|
| 110 | a const value of <code>X</code>. |
|---|
| 111 | |
|---|
| 112 | <p> |
|---|
| 113 | |
|---|
| 114 | <table border=1> |
|---|
| 115 | <tr><th colspan=3 align=center><code>UniformRandomNumberGenerator</code> |
|---|
| 116 | requirements</th></tr> |
|---|
| 117 | <tr><td>expression</td><td>return type</td> |
|---|
| 118 | <td>pre/post-condition</td></tr> |
|---|
| 119 | <tr><td><code>X::has_fixed_range</code></td><td><code>bool</code></td> |
|---|
| 120 | <td>compile-time constant; if <code>true</code>, the range on which |
|---|
| 121 | the random numbers are uniformly distributed is known at compile-time |
|---|
| 122 | and members <code>min_value</code> and <code>max_value</code> |
|---|
| 123 | exist. <em>Note:</em> This flag may also be <code>false</code> due to |
|---|
| 124 | compiler limitations.</td></tr> |
|---|
| 125 | <tr><td><code>X::min_value</code></td><td><code>T</code></td> |
|---|
| 126 | <td>compile-time constant; <code>min_value</code> is equal to |
|---|
| 127 | <code>v.min()</code></td></tr> |
|---|
| 128 | <tr><td><code>X::max_value</code></td><td><code>T</code></td> |
|---|
| 129 | <td>compile-time constant; <code>max_value</code> is equal to |
|---|
| 130 | <code>v.max()</code></td></tr> |
|---|
| 131 | <tr><td><code>v.min()</code></td><td><code>T</code></td> |
|---|
| 132 | <td>tight lower bound on the set of all values returned by |
|---|
| 133 | <code>operator()</code>. The return value of this function shall not |
|---|
| 134 | change during the lifetime of the object.</td></tr> |
|---|
| 135 | <tr><td><code>v.max()</code></td><td><code>T</code></td> |
|---|
| 136 | <td>if <code>std::numeric_limits<T>::is_integer</code>, tight |
|---|
| 137 | upper bound on the set of all values returned by |
|---|
| 138 | <code>operator()</code>, otherwise, the smallest representable number |
|---|
| 139 | larger than the tight upper bound on the set of all values returned by |
|---|
| 140 | <code>operator()</code>. In any case, the return value of this |
|---|
| 141 | function shall not change during the lifetime of the |
|---|
| 142 | object.</code></td></tr> |
|---|
| 143 | </table> |
|---|
| 144 | |
|---|
| 145 | <p> |
|---|
| 146 | The member functions <code>min</code>, <code>max</code>, and |
|---|
| 147 | <code>operator()</code> shall have amortized constant time complexity. |
|---|
| 148 | |
|---|
| 149 | <p> |
|---|
| 150 | <em>Note:</em> For integer generators (i.e. integer <code>T</code>), |
|---|
| 151 | the generated values <code>x</code> fulfill <code>min() <= x <= |
|---|
| 152 | max()</code>, for non-integer generators (i.e. non-integer |
|---|
| 153 | <code>T</code>), the generated values <code>x</code> fulfill |
|---|
| 154 | <code>min() <= x < max()</code>. |
|---|
| 155 | <br> |
|---|
| 156 | <em>Rationale:</em> The range description with <code>min</code> and |
|---|
| 157 | <code>max</code> serves two purposes. First, it allows scaling of the |
|---|
| 158 | values to some canonical range, such as [0..1). Second, it describes |
|---|
| 159 | the significant bits of the values, which may be relevant for further |
|---|
| 160 | processing. |
|---|
| 161 | <br> |
|---|
| 162 | The range is a closed interval [min,max] for integers, because the |
|---|
| 163 | underlying type may not be able to represent the half-open interval |
|---|
| 164 | [min,max+1). It is a half-open interval [min, max) for non-integers, |
|---|
| 165 | because this is much more practical for borderline cases of continuous |
|---|
| 166 | distributions. |
|---|
| 167 | <p> |
|---|
| 168 | |
|---|
| 169 | <em>Note:</em> The UniformRandomNumberGenerator concept does not |
|---|
| 170 | require <code>operator()(long)</code> and thus it does not fulfill the |
|---|
| 171 | RandomNumberGenerator (std:25.2.11 [lib.alg.random.shuffle]) |
|---|
| 172 | requirements. Use the |
|---|
| 173 | <a href="random-misc.html#random_number_generator"><code>random_number_generator</code></a> |
|---|
| 174 | adapter for that. |
|---|
| 175 | <br> |
|---|
| 176 | |
|---|
| 177 | <em>Rationale:</em> <code>operator()(long)</code> is not provided, |
|---|
| 178 | because mapping the output of some generator with integer range to a |
|---|
| 179 | different integer range is not trivial. |
|---|
| 180 | |
|---|
| 181 | |
|---|
| 182 | <h2><a name="nondet-rng">Non-deterministic Uniform Random Number |
|---|
| 183 | Generator</a></h2> |
|---|
| 184 | |
|---|
| 185 | A non-deterministic uniform random number generator is a |
|---|
| 186 | UniformRandomNumberGenerator that is based on some stochastic process. |
|---|
| 187 | Thus, it provides a sequence of truly-random numbers. Examples for |
|---|
| 188 | such processes are nuclear decay, noise of a Zehner diode, tunneling |
|---|
| 189 | of quantum particles, rolling a die, drawing from an urn, and tossing |
|---|
| 190 | a coin. Depending on the environment, inter-arrival times of network |
|---|
| 191 | packets or keyboard events may be close approximations of stochastic |
|---|
| 192 | processes. |
|---|
| 193 | <p> |
|---|
| 194 | |
|---|
| 195 | The class |
|---|
| 196 | <code><a href="nondet_random.html#random_device">random_device</a></code> |
|---|
| 197 | is a model for a non-deterministic random number generator. |
|---|
| 198 | |
|---|
| 199 | <p> |
|---|
| 200 | |
|---|
| 201 | <em>Note:</em> This type of random-number generator is useful for |
|---|
| 202 | security applications, where it is important to prevent that an |
|---|
| 203 | outside attacker guesses the numbers and thus obtains your |
|---|
| 204 | encryption or authentication key. Thus, models of this concept should |
|---|
| 205 | be cautious not to leak any information, to the extent possible by the |
|---|
| 206 | environment. For example, it might be advisable to explicitly clear |
|---|
| 207 | any temporary storage as soon as it is no longer needed. |
|---|
| 208 | |
|---|
| 209 | |
|---|
| 210 | <h2><a name="pseudo-rng">Pseudo-Random Number Generator</a></h2> |
|---|
| 211 | |
|---|
| 212 | A pseudo-random number generator is a UniformRandomNumberGenerator |
|---|
| 213 | which provides a deterministic sequence of pseudo-random numbers, |
|---|
| 214 | based on some algorithm and internal state. Linear congruential and |
|---|
| 215 | inversive congruential generators are examples of such pseudo-random |
|---|
| 216 | number generators. Often, these generators are very sensitive to |
|---|
| 217 | their parameters. In order to prevent wrong implementations from |
|---|
| 218 | being used, an external testsuite should check that the generated |
|---|
| 219 | sequence and the validation value provided do indeed match. |
|---|
| 220 | <p> |
|---|
| 221 | |
|---|
| 222 | Donald E. Knuth gives an extensive overview on pseudo-random number |
|---|
| 223 | generation in his book "The Art of Computer Programming, Vol. 2, 3rd |
|---|
| 224 | edition, Addison-Wesley, 1997". The descriptions for the specific |
|---|
| 225 | generators contain additional references. |
|---|
| 226 | <p> |
|---|
| 227 | |
|---|
| 228 | <em>Note:</em> Because the state of a pseudo-random number generator |
|---|
| 229 | is necessarily finite, the sequence of numbers returned by the |
|---|
| 230 | generator will loop eventually. |
|---|
| 231 | |
|---|
| 232 | <p> |
|---|
| 233 | In addition to the UniformRandomNumberGenerator requirements, a |
|---|
| 234 | pseudo-random number generator has some additional requirements. In |
|---|
| 235 | the following table, <code>X</code> denotes a pseudo-random number |
|---|
| 236 | generator class returning objects of type <code>T</code>, |
|---|
| 237 | <code>x</code> is a value of <code>T</code>, <code>u</code> is a value |
|---|
| 238 | of <code>X</code>, and <code>v</code> is a <code>const</code> value of |
|---|
| 239 | <code>X</code>. |
|---|
| 240 | |
|---|
| 241 | <p> |
|---|
| 242 | |
|---|
| 243 | <table border=1> |
|---|
| 244 | <tr><th colspan=3 align=center><code>PseudoRandomNumberGenerator</code> |
|---|
| 245 | requirements</th></tr> |
|---|
| 246 | <tr><td>expression</td><td>return type</td> |
|---|
| 247 | <td>pre/post-condition</td></tr> |
|---|
| 248 | <tr><td><code>X()</code></td><td>-</td> |
|---|
| 249 | <td>creates a generator in some implementation-defined |
|---|
| 250 | state. <em>Note:</em> Several generators thusly created may possibly |
|---|
| 251 | produce dependent or identical sequences of random numbers.</td></tr> |
|---|
| 252 | <tr><td><code>explicit X(...)</code></td><td>-</td> |
|---|
| 253 | <td>creates a generator with user-provided state; the implementation |
|---|
| 254 | shall specify the constructor argument(s)</td></tr> |
|---|
| 255 | <tr><td><code>u.seed(...)</code></td><td>void</td> |
|---|
| 256 | <td>sets the current state according to the argument(s); at least |
|---|
| 257 | functions with the same signature as the non-default |
|---|
| 258 | constructor(s) shall be provided. |
|---|
| 259 | <tr><td><code>X::validation(x)</code></td><td><code>bool</code></td> |
|---|
| 260 | <td>compares the pre-computed and hardcoded 10001th element in the |
|---|
| 261 | generator's random number sequence with <code>x</code>. The generator |
|---|
| 262 | must have been constructed by its default constructor and |
|---|
| 263 | <code>seed</code> must not have been called for the validation to |
|---|
| 264 | be meaningful. |
|---|
| 265 | </table> |
|---|
| 266 | |
|---|
| 267 | <p> |
|---|
| 268 | |
|---|
| 269 | <em>Note:</em> The <code>seed</code> member function is similar to the |
|---|
| 270 | <code>assign</code> member function in STL containers. However, the |
|---|
| 271 | naming did not seem appropriate. |
|---|
| 272 | |
|---|
| 273 | <p> |
|---|
| 274 | |
|---|
| 275 | Classes which model a pseudo-random number generator shall also model |
|---|
| 276 | EqualityComparable, i.e. implement <code>operator==</code>. Two |
|---|
| 277 | pseudo-random number generators are defined to be <em>equivalent</em> |
|---|
| 278 | if they both return an identical sequence of numbers starting from a |
|---|
| 279 | given state. |
|---|
| 280 | <p> |
|---|
| 281 | Classes which model a pseudo-random number generator should also model |
|---|
| 282 | the Streamable concept, i.e. implement <code>operator<<</code> |
|---|
| 283 | and <code>operator>></code>. If so, |
|---|
| 284 | <code>operator<<</code> writes all current state of the |
|---|
| 285 | pseudo-random number generator to the given <code>ostream</code> so |
|---|
| 286 | that <code>operator>></code> can restore the state at a later |
|---|
| 287 | time. The state shall be written in a platform-independent manner, |
|---|
| 288 | but it is assumed that the <code>locale</code>s used for writing and |
|---|
| 289 | reading be the same. |
|---|
| 290 | |
|---|
| 291 | The pseudo-random number generator with the restored state and the |
|---|
| 292 | original at the just-written state shall be equivalent. |
|---|
| 293 | <p> |
|---|
| 294 | |
|---|
| 295 | Classes which model a pseudo-random number generator may also model |
|---|
| 296 | the CopyConstructible and Assignable concepts. However, note that the |
|---|
| 297 | sequences of the original and the copy are strongly correlated (in |
|---|
| 298 | fact, they are identical), which may make them unsuitable for some |
|---|
| 299 | problem domains. Thus, copying pseudo-random number generators is |
|---|
| 300 | discouraged; they should always be passed by (non-<code>const</code>) |
|---|
| 301 | reference. |
|---|
| 302 | |
|---|
| 303 | <p> |
|---|
| 304 | |
|---|
| 305 | The classes |
|---|
| 306 | <code><a href="random-generators.html#rand48">rand48</a></code>, |
|---|
| 307 | <code><a href="random-generators.html#linear_congruential">minstd_rand</a></code>, |
|---|
| 308 | and |
|---|
| 309 | <code><a href="random-generators.html#mersenne_twister">mt19937</a></code> |
|---|
| 310 | are models for a pseudo-random number generator. |
|---|
| 311 | |
|---|
| 312 | <p> |
|---|
| 313 | <em>Note:</em> This type of random-number generator is useful for |
|---|
| 314 | numerics, games and testing. The non-zero arguments constructor(s) |
|---|
| 315 | and the <code>seed()</code> member function(s) allow for a |
|---|
| 316 | user-provided state to be installed in the generator. This is useful |
|---|
| 317 | for debugging Monte-Carlo algorithms and analyzing particular test |
|---|
| 318 | scenarios. The Streamable concept allows to save/restore the state of |
|---|
| 319 | the generator, for example to re-run a test suite at a later time. |
|---|
| 320 | |
|---|
| 321 | <h2><a name="random-dist">Random Distribution</a></h2> |
|---|
| 322 | |
|---|
| 323 | A radom distribution produces random numbers distributed according to |
|---|
| 324 | some distribution, given uniformly distributed random values as input. |
|---|
| 325 | |
|---|
| 326 | In the following table, <code>X</code> denotes a random distribution |
|---|
| 327 | class returning objects of type <code>T</code>, <code>u</code> is a |
|---|
| 328 | value of <code>X</code>, <code>x</code> is a (possibly const) |
|---|
| 329 | value of <code>X</code>, and <code>e</code> is an lvalue of an |
|---|
| 330 | arbitrary type that meets the requirements of a uniform random number |
|---|
| 331 | generator, returning values of type <code>U</code>. |
|---|
| 332 | <p> |
|---|
| 333 | |
|---|
| 334 | |
|---|
| 335 | <table border=1> |
|---|
| 336 | <tr> |
|---|
| 337 | <th colspan=4 align=center>Random distribution requirements |
|---|
| 338 | (in addition to number generator, |
|---|
| 339 | <code>CopyConstructible</code>, and <code>Assignable</code>)</th> |
|---|
| 340 | <tr><td>expression</td><td>return type</td> |
|---|
| 341 | <td>pre/post-condition</td> |
|---|
| 342 | <td>complexity</td> |
|---|
| 343 | </tr> |
|---|
| 344 | |
|---|
| 345 | <tr> |
|---|
| 346 | <td><code>X::input_type</code></td> |
|---|
| 347 | <td>U</td> |
|---|
| 348 | <td>-</td> |
|---|
| 349 | <td>compile-time</td> |
|---|
| 350 | </tr> |
|---|
| 351 | |
|---|
| 352 | <tr> |
|---|
| 353 | <td><code>u.reset()</code></td> |
|---|
| 354 | <td><code>void</code></td> |
|---|
| 355 | <td>subsequent uses of <code>u</code> do not depend on values |
|---|
| 356 | produced by <code>e</code> prior to invoking <code>reset</code>.</td> |
|---|
| 357 | <td>constant</td> |
|---|
| 358 | </tr> |
|---|
| 359 | |
|---|
| 360 | <tr> |
|---|
| 361 | <td><code>u(e)</code></td> |
|---|
| 362 | <td><code>T</code></td> |
|---|
| 363 | <td>the sequence of numbers returned by successive invocations with |
|---|
| 364 | the same object <code>e</code> is randomly distributed with some |
|---|
| 365 | probability density function p(x)</td> |
|---|
| 366 | <td>amortized constant number of invocations of <code>e</code></td> |
|---|
| 367 | </tr> |
|---|
| 368 | |
|---|
| 369 | <tr> |
|---|
| 370 | <td><code>os << x</code></td> |
|---|
| 371 | <td><code>std::ostream&</code></td> |
|---|
| 372 | <td>writes a textual representation for the parameters and additional |
|---|
| 373 | internal data of the distribution <code>x</code> to <code>os</code>. |
|---|
| 374 | <br> |
|---|
| 375 | post: The <code>os.<em>fmtflags</em></code> and fill character are |
|---|
| 376 | unchanged.</td> |
|---|
| 377 | <td>O(size of state)</td> |
|---|
| 378 | </tr> |
|---|
| 379 | |
|---|
| 380 | <tr> |
|---|
| 381 | <td><code>is >> u</code></td> |
|---|
| 382 | <td><code>std::istream&</code></td> |
|---|
| 383 | <td>restores the parameters and additional internal data of the |
|---|
| 384 | distribution <code>u</code>. |
|---|
| 385 | <br> |
|---|
| 386 | pre: <code>is</code> provides a textual representation that was |
|---|
| 387 | previously written by <code>operator<<</code> |
|---|
| 388 | <br> |
|---|
| 389 | post: The <code>is.<em>fmtflags</em></code> are unchanged.</td> |
|---|
| 390 | <td>O(size of state)</td> |
|---|
| 391 | </tr> |
|---|
| 392 | |
|---|
| 393 | </table> |
|---|
| 394 | <p> |
|---|
| 395 | |
|---|
| 396 | Additional requirements: The sequence of numbers produced by |
|---|
| 397 | repeated invocations of <code>x(e)</code> does not change whether or |
|---|
| 398 | not <code>os << x</code> is invoked between any of the |
|---|
| 399 | invocations <code>x(e)</code>. If a textual representation |
|---|
| 400 | is written using <code>os << x</code> and that representation |
|---|
| 401 | is restored into the same or a different object <code>y</code> of the |
|---|
| 402 | same type using <code>is >> y</code>, repeated invocations of |
|---|
| 403 | <code>y(e)</code> produce the same sequence of random numbers as would |
|---|
| 404 | repeated invocations of <code>x(e)</code>. |
|---|
| 405 | <p> |
|---|
| 406 | |
|---|
| 407 | <h2><a name="quasi-rng">Quasi-Random Number Generators</a></h2> |
|---|
| 408 | |
|---|
| 409 | A quasi-random number generator is a Number Generator which provides a |
|---|
| 410 | deterministic sequence of numbers, based on some algorithm and |
|---|
| 411 | internal state. The numbers do not have any statistical properties |
|---|
| 412 | (such as uniform distribution or independence of successive values). |
|---|
| 413 | |
|---|
| 414 | <p> |
|---|
| 415 | |
|---|
| 416 | <em>Note:</em> Quasi-random number generators are useful for |
|---|
| 417 | Monte-Carlo integrations where specially crafted sequences of random |
|---|
| 418 | numbers will make the approximation converge faster. |
|---|
| 419 | |
|---|
| 420 | <p> |
|---|
| 421 | |
|---|
| 422 | <em>[Does anyone have a model?]</em> |
|---|
| 423 | |
|---|
| 424 | <p> |
|---|
| 425 | <hr> |
|---|
| 426 | Jens Maurer, 2000-02-23 |
|---|
| 427 | |
|---|
| 428 | </body> |
|---|
| 429 | </html> |
|---|