PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3
Jetpack – WP Security, Backup, Speed, & Growth v16.3
16.3 16.3-beta 16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 All 508 releases
← All changes | _inc/lib/class.jetpack-password-checker.php +1288 -0 16.2-beta → 16.3 View file →
@@ -1,0 +1,1288 @@
1 +<?php //phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2 +/**
3 + * The password strength checker.
4 + *
5 + * @package automattic/jetpack
6 + */
7 +
8 +/**
9 + * Checks passwords strength.
10 + */
11 +class Jetpack_Password_Checker {
12 +
13 + /**
14 + * Minimum entropy bits a password should contain. 36 bits of entropy is considered
15 + * to be a reasonable password, 28 stands for a weak one.
16 + *
17 + * @const Integer
18 + */
19 + const MINIMUM_BITS = 28;
20 +
21 + /**
22 + * Currently tested password.
23 + *
24 + * @var String
25 + */
26 + public $password = '';
27 +
28 + /**
29 + * Test results array.
30 + *
31 + * @var Array
32 + */
33 + public $test_results = '';
34 +
35 + /**
36 + * Current password score.
37 + *
38 + * @var Integer
39 + */
40 + public $score = 0;
41 +
42 + /**
43 + * Current multiplier affecting the score.
44 + *
45 + * @var Integer
46 + */
47 + public $multiplier = 4;
48 +
49 + /**
50 + * A common password disallow list, which on match will immediately disqualify the password.
51 + *
52 + * @var Array
53 + */
54 + public $common_passwords = array();
55 +
56 + /**
57 + * Minimum password length setting.
58 + *
59 + * @var Integer
60 + */
61 + public $min_password_length = 6;
62 +
63 + /**
64 + * User defined strings that passwords need to be tested for a match against.
65 + *
66 + * @var Array
67 + */
68 + private $user_strings_to_test = array();
69 +
70 + /**
71 + * The user object for whom the password is being tested.
72 + *
73 + * @var WP_User
74 + */
75 + protected $user;
76 +
77 + /**
78 + * The user identifier for whom the password is being tested, used if there's no user object.
79 + *
80 + * @var WP_User
81 + */
82 + protected $user_id;
83 +
84 + /**
85 + * Creates an instance of the password checker class for the specified user, or
86 + * defaults to the currently logged in user.
87 + *
88 + * @param Mixed $user can be an integer ID, or a WP_User object.
89 + */
90 + public function __construct( $user = null ) {
91 +
92 + /**
93 + * Filters Jetpack's password strength enforcement settings. You can supply your own passwords
94 + * that should not be used for authenticating in addition to weak and easy to guess strings for
95 + * each user. For example, you can add passwords from known password databases to avoid compromised
96 + * password usage.
97 + *
98 + * @since 7.2.0
99 + *
100 + * @param array $restricted_passwords strings that are forbidden for use as passwords.
101 + */
102 + $this->common_passwords = apply_filters( 'jetpack_password_checker_restricted_strings', array() );
103 +
104 + if ( $user === null ) {
105 + $this->user_id = get_current_user_id();
106 + } elseif ( is_object( $user ) && isset( $user->ID ) ) {
107 +
108 + // Existing user, using their ID.
109 + $this->user_id = $user->ID;
110 +
111 + } elseif ( is_object( $user ) ) {
112 +
113 + // Newly created user, using existing data.
114 + $this->user = $user;
115 + $this->user_id = 'new_user';
116 +
117 + } else {
118 + $this->user_id = $user;
119 + }
120 + $this->min_password_length = apply_filters( 'better_password_min_length', $this->min_password_length );
121 + }
122 +
123 + /**
124 + * Run tests against a password.
125 + *
126 + * @param String $password the tested string.
127 + * @param Boolean $required_only only test against required conditions, defaults to false.
128 + * @return array $results an array containing failed and passed test results.
129 + */
130 + public function test( $password, $required_only = false ) {
131 +
132 + $this->password = $password;
133 + $results = $this->run_tests( $this->list_tests(), $required_only );
134 +
135 + // If we've failed on the required tests, return now.
136 + if ( ! empty( $results['failed'] ) ) {
137 + return array(
138 + 'passed' => false,
139 + 'test_results' => $results,
140 + );
141 + }
142 +
143 + /**
144 + * Filters Jetpack's password strength enforcement settings. You can modify the minimum
145 + * entropy bits requirement using this filter.
146 + *
147 + * @since 7.2.0
148 + *
149 + * @param array $minimum_entropy_bits minimum entropy bits requirement.
150 + */
151 + $bits = apply_filters( 'jetpack_password_checker_minimum_entropy_bits', self::MINIMUM_BITS );
152 + $entropy_bits = $this->calculate_entropy_bits( $this->password );
153 +
154 + // If we have failed the entropy bits test, run the regex tests so we can suggest improvements.
155 + if ( $entropy_bits < $bits ) {
156 + $results['failed']['entropy_bits'] = $entropy_bits;
157 + $results = array_merge(
158 + $results,
159 + $this->run_tests( $this->list_tests( 'preg_match' ), false )
160 + );
161 + }
162 +
163 + return( array(
164 + 'passed' => empty( $results['failed'] ),
165 + 'test_results' => $results,
166 + ) );
167 + }
168 +
169 + /**
170 + * Run the tests using the currently set up object values.
171 + *
172 + * @param array $tests tests to run.
173 + * @param Boolean $required_only whether to run only required tests.
174 + * @return array test results.
175 + */
176 + protected function run_tests( $tests, $required_only = false ) {
177 +
178 + $results = array(
179 + 'passed' => array(),
180 + 'failed' => array(),
181 + );
182 +
183 + foreach ( $tests as $test_type => $section_tests ) {
184 + foreach ( $section_tests as $test_name => $test_data ) {
185 +
186 + // Skip non-required tests if required_only param is set.
187 + if ( $required_only && ! $test_data['required'] ) {
188 + continue;
189 + }
190 +
191 + $test_function = 'test_' . $test_type;
192 +
193 + $result = call_user_func( array( $this, $test_function ), $test_data );
194 +
195 + if ( $result ) {
196 + $results['passed'][] = array( 'test_name' => $test_name );
197 + } else {
198 + $results['failed'][] = array(
199 + 'test_name' => $test_name,
200 + 'explanation' => $test_data['error'],
201 + );
202 +
203 + if ( isset( $test_data['fail_immediately'] ) ) {
204 + return $results;
205 + }
206 + }
207 + }
208 + }
209 +
210 + return $results;
211 + }
212 +
213 + /**
214 + * Returns a list of tests that need to be run on password strings.
215 + *
216 + * @param array $sections only return specific sections with the passed keys, defaults to all.
217 + * @return array test descriptions.
218 + */
219 + protected function list_tests( $sections = false ) {
220 + // Note: these should be in order of priority.
221 + $tests = array(
222 + 'preg_match' => array(
223 + 'no_backslashes' => array(
224 + 'pattern' => '^[^\\\\]*$',
225 + 'error' => __( 'Passwords may not contain the character "\".', 'jetpack' ),
226 + 'required' => true,
227 + 'fail_immediately' => true,
228 + ),
229 + 'minimum_length' => array(
230 + 'pattern' => '^.{' . $this->min_password_length . ',}',
231 + /* translators: %d is a number of characters in the password. */
232 + 'error' => sprintf( __( 'Password must be at least %d characters.', 'jetpack' ), $this->min_password_length ),
233 + 'required' => true,
234 + 'fail_immediately' => true,
235 + ),
236 + 'has_mixed_case' => array(
237 + 'pattern' => '([a-z].*?[A-Z]|[A-Z].*?[a-z])',
238 + 'error' => __( 'This password is too easy to guess: you can improve it by adding additional uppercase letters, lowercase letters, or numbers.', 'jetpack' ),
239 + 'trim' => true,
240 + 'required' => false,
241 + ),
242 + 'has_digit' => array(
243 + 'pattern' => '\d',
244 + 'error' => __( 'This password is too easy to guess: you can improve it by mixing both letters and numbers.', 'jetpack' ),
245 + 'trim' => false,
246 + 'required' => false,
247 + ),
248 + 'has_special_char' => array(
249 + 'pattern' => '[^a-zA-Z\d]',
250 + 'error' => __( 'This password is too easy to guess: you can improve it by including special characters such as !#=?*&.', 'jetpack' ),
251 + 'required' => false,
252 + ),
253 + ),
254 + 'compare_to_list' => array(
255 + 'not_a_common_password' => array(
256 + 'list_callback' => 'get_common_passwords',
257 + 'compare_callback' => 'negative_in_array',
258 + 'error' => __( 'This is a very common password. Choose something that will be harder for others to guess.', 'jetpack' ),
259 + 'required' => true,
260 + ),
261 + 'not_same_as_other_user_data' => array(
262 + 'list_callback' => 'get_other_user_data',
263 + 'compare_callback' => 'test_not_same_as_other_user_data',
264 + 'error' => __( 'Your password is too weak: Looks like you\'re including easy to guess information about yourself. Try something a little more unique.', 'jetpack' ),
265 + 'required' => true,
266 + ),
267 + ),
268 + );
269 +
270 + /**
271 + * Filters Jetpack's password strength enforcement settings. You can determine the tests run
272 + * and their order based on whatever criteria you wish to specify.
273 + *
274 + * @since 7.2.0
275 + *
276 + * @param array $minimum_entropy_bits minimum entropy bits requirement.
277 + */
278 + $tests = apply_filters( 'jetpack_password_checker_tests', $tests );
279 +
280 + if ( ! $sections ) {
281 + return $tests;
282 + }
283 +
284 + $sections = (array) $sections;
285 + return array_intersect_key( $tests, array_flip( $sections ) );
286 + }
287 +
288 + /**
289 + * Provides the regular expression tester functionality.
290 + *
291 + * @param array $test_data the current test data.
292 + * @return Boolean does the test pass?
293 + */
294 + protected function test_preg_match( $test_data ) {
295 + $password = stripslashes( $this->password );
296 +
297 + if ( isset( $test_data['trim'] ) ) {
298 + $password = substr( $password, 1, -1 );
299 + }
300 +
301 + if ( ! preg_match( '/' . $test_data['pattern'] . '/u', $password ) ) {
302 + return false;
303 + }
304 +
305 + return true;
306 + }
307 +
308 + /**
309 + * Provides the comparison tester functionality.
310 + *
311 + * @param array $test_data the current test data.
312 + * @return Boolean does the test pass?
313 + */
314 + protected function test_compare_to_list( $test_data ) {
315 + $list_callback = $test_data['list_callback'];
316 + $compare_callback = $test_data['compare_callback'];
317 +
318 + if (
319 + ! is_callable( array( $this, $list_callback ) )
320 + || ! is_callable( array( $this, $compare_callback ) )
321 + ) {
322 + return false;
323 + }
324 +
325 + $list = call_user_func( array( $this, $list_callback ) );
326 + if ( empty( $list ) ) {
327 + return true;
328 + }
329 +
330 + return call_user_func( array( $this, $compare_callback ), $this->password, $list );
331 + }
332 +
333 + /**
334 + * Getter for the common password list.
335 + *
336 + * @return array common passwords.
337 + */
338 + protected function get_common_passwords() {
339 + return $this->common_passwords;
340 + }
341 +
342 + /**
343 + * Returns the widely known user data that cannot be used in the password to avoid
344 + * predictable strings.
345 + *
346 + * @return array user data.
347 + */
348 + protected function get_other_user_data() {
349 +
350 + if ( ! isset( $this->user ) ) {
351 + $user_data = get_userdata( $this->user_id );
352 +
353 + $first_name = get_user_meta( $user_data->ID, 'first_name', true );
354 + $last_name = get_user_meta( $user_data->ID, 'last_name', true );
355 + $nickname = get_user_meta( $user_data->ID, 'nickname', true );
356 +
357 + $this->add_user_strings_to_test( $nickname );
358 + $this->add_user_strings_to_test( $user_data->user_nicename );
359 + $this->add_user_strings_to_test( $user_data->display_name );
360 + } else {
361 + $user_data = $this->user;
362 +
363 + $first_name = $user_data->first_name;
364 + $last_name = $user_data->last_name;
365 + }
366 + $email_username = substr( $user_data->user_email, 0, strpos( $user_data->user_email, '@' ) );
367 +
368 + $this->add_user_strings_to_test( $user_data->user_email );
369 + $this->add_user_strings_to_test( $email_username, '.' );
370 + $this->add_user_strings_to_test( $first_name );
371 + $this->add_user_strings_to_test( $last_name );
372 +
373 + return $this->user_strings_to_test;
374 + }
375 +
376 + /**
377 + * Compare the password for matches with known user data.
378 + *
379 + * @param String $password the string to be tested.
380 + * @param array $strings_to_test known user data.
381 + * @return Boolean does the test pass?
382 + */
383 + protected function test_not_same_as_other_user_data( $password, $strings_to_test ) {
384 + $password_lowercase = strtolower( $password );
385 + foreach ( array_unique( $strings_to_test ) as $string ) {
386 + if ( empty( $string ) ) {
387 + continue;
388 + }
389 +
390 + $string = strtolower( $string );
391 + $string_reversed = strrev( $string );
392 +
393 + if ( $password_lowercase === $string || $password_lowercase === $string_reversed ) {
394 + return false;
395 + }
396 +
397 + // Also check for the string or reversed string with any numbers just stuck to the end to catch things like bob123 as passwords.
398 + if (
399 + preg_match( '/^' . preg_quote( $string, '/' ) . '\d+$/', $password_lowercase )
400 + || preg_match( '/^' . preg_quote( $string_reversed, '/' ) . '\d+$/', $password_lowercase )
401 + ) {
402 + return false;
403 + }
404 + }
405 + return true;
406 + }
407 +
408 + /**
409 + * A shorthand for the not in array construct.
410 + *
411 + * @param Mixed $needle the needle.
412 + * @param array $haystack the haystack.
413 + * @return bool is the needle not in the haystack?
414 + */
415 + protected function negative_in_array( $needle, $haystack ) {
416 + if ( in_array( $needle, $haystack, true ) ) {
417 + return false;
418 + }
419 +
420 + return true;
421 + }
422 +
423 + /**
424 + * A helper function used to break a single string into its constituents so
425 + * that both the full string and its constituents and any variants thereof
426 + * can be tested against the password.
427 + *
428 + * @param String $string the string to be broken down.
429 + * @param String $explode_delimiter delimiter.
430 + * @return NULL|Array array of fragments, or NULL on empty string.
431 + */
432 + protected function add_user_strings_to_test( $string, $explode_delimiter = ' ' ) {
433 +
434 + // Don't check against empty strings.
435 + if ( empty( $string ) ) {
436 + return;
437 + }
438 +
439 + $strings = explode( $explode_delimiter, $string );
440 +
441 + // Remove any non alpha numeric characters from the strings to check against.
442 + foreach ( $strings as $key => $_string ) {
443 + $strings[ $key ] = preg_replace( '/[^a-zA-Z0-9]/', '', $_string );
444 + }
445 +
446 + // Check the original too.
447 + $strings[] = $string;
448 +
449 + // Check the original minus non alpha numeric characters.
450 + $strings[] = preg_replace( '/[^a-zA-Z0-9]/', '', $string );
451 +
452 + // Remove any empty strings.
453 + $strings = array_filter( $strings );
454 + $this->user_strings_to_test = array_merge( $this->user_strings_to_test, $strings );
455 + }
456 +
457 + /**
458 + * Return a character set size that is used in the string.
459 + *
460 + * @param String $password the password.
461 + * @return Integer number of different character sets in use.
462 + */
463 + protected function get_charset_size( $password ) {
464 + $size = 0;
465 +
466 + // Lowercase a-z.
467 + if ( preg_match( '/[a-z]/', $password ) ) {
468 + $size += 26;
469 + }
470 +
471 + // Uppercase A-Z.
472 + if ( preg_match( '/[A-Z]/', substr( $password, 1, -1 ) ) ) {
473 + $size += 26;
474 + }
475 +
476 + // Digits.
477 + if ( preg_match( '/\d/', substr( $password, 1, -1 ) ) ) {
478 + $size += 10;
479 + }
480 +
481 + // Over digits symbols.
482 + if ( preg_match( '/[!|@|#|$|%|^|&|*|(|)]/', $password ) ) {
483 + $size += 10;
484 + }
485 +
486 + // Other symbols.
487 + if ( preg_match( '#[`|~|-|_|=|+|\[|{|\]|}|\\|\|;:\'",<\.>/\?]#', $password ) ) {
488 + $size += 20;
489 + }
490 +
491 + // Spaces.
492 + if ( strpos( $password, ' ' ) ) {
493 + ++$size;
494 + }
495 +
496 + return $size;
497 + }
498 +
499 + /**
500 + * Shorthand for getting a character index.
501 + *
502 + * @param String $char character.
503 + * @return Integer the character code.
504 + */
505 + protected function get_char_index( $char ) {
506 + $char = strtolower( $char[0] );
507 + if ( $char < 'a' || $char > 'z' ) {
508 + return 0;
509 + } else {
510 + return ord( $char[0] ) - ord( 'a' ) + 1;
511 + }
512 + }
513 +
514 + /**
515 + * This is the password strength calculation algorithm, based on the formula H = L(logN/log2).
516 + *
517 + * H = Entropy
518 + * L = String length (the for iterator)
519 + * N = Our charset size, via get_charset_size()
520 + *
521 + * @see https://en.wikipedia.org/wiki/Password_strength#Random_passwords
522 + *
523 + * On top of the base formula, we're also multiplying the bits of entropy for every char
524 + * by 1 - (the probabily of it following the previous char)
525 + * i.e.: the probablity of U following Q is ~0.84. If our password contains this pair of characters,
526 + * the u char will only add ( 0.16^2 * charset_score ) to our total of entropy bits.
527 + *
528 + * @param String $password the password.
529 + */
530 + protected function calculate_entropy_bits( $password ) {
531 + $bits = 0;
532 + $charset_score = log( $this->get_charset_size( $password ) ) / log( 2 );
533 +
534 + $aidx = $this->get_char_index( $password[0] );
535 + $length = strlen( $password );
536 +
537 + for ( $b = 1; $b < $length; $b++ ) {
538 + $bidx = $this->get_char_index( $password[ $b ] );
539 +
540 + // 27 = number of chars in the index (a-z,' ').
541 + $c = 1.0 - $this->frequency_table[ $aidx * 27 + $bidx ];
542 + $bits += $charset_score * $c * $c;
543 +
544 + // Move on to next pair.
545 + $aidx = $bidx;
546 + }
547 +
548 + return $bits;
549 + }
550 +
551 + /**
552 + * A frequency table of character pairs, starting with ' ' then ' a', ' b' [...] , 'a ', 'aa' etc.
553 + *
554 + * @see http://rumkin.com/tools/password/passchk.php
555 + * @var Array
556 + */
557 + public $frequency_table = array(
558 + 0.23653710453418866,
559 + 0.04577693541332556,
560 + 0.03449832337075375,
561 + 0.042918209651552706,
562 + 0.037390873305146524,
563 + 0.028509112115468728,
564 + 0.02350896632162123,
565 + 0.022188657238664526,
566 + 0.028429800262428927,
567 + 0.04357019973757107,
568 + 0.00913602565971716,
569 + 0.03223093745443942,
570 + 0.02235311269864412,
571 + 0.04438081352966905,
572 + 0.04512377897652719,
573 + 0.020055401662049863,
574 + 0.055903192885260244,
575 + 0.0024388394809739026,
576 + 0.035207464644991984,
577 + 0.07355941099285611,
578 + 0.036905671380667734,
579 + 0.026134421927394666,
580 + 0.023787724158040528,
581 + 0.011352092141711621,
582 + 0.0032354570637119114,
583 + 0.005986878553725033,
584 + 0.008861933226417843,
585 + 0.11511532293337222,
586 + 0.027556203528211108,
587 + 0.024331243621519172,
588 + 0.039266365359381834,
589 + 0.031599941682461,
590 + 0.014403265782183991,
591 + 0.015480973902901297,
592 + 0.027770812071730572,
593 + 0.00942761335471643,
594 + 0.039872867764980315,
595 + 0.0078122175244204695,
596 + 0.02808456043154979,
597 + 0.08429100451960927,
598 + 0.04688963405744277,
599 + 0.13831170724595424,
600 + 0.002540311998833649,
601 + 0.025211838460416972,
602 + 0.001543082081936142,
603 + 0.09519638431258201,
604 + 0.061845750109345385,
605 + 0.08907071001603732,
606 + 0.02137571074500656,
607 + 0.027093162268552268,
608 + 0.005521504592506197,
609 + 0.003023181221752442,
610 + 0.007086747339262283,
611 + 0.010262720513194342,
612 + 0.08785070710016038,
613 + 0.14617757690625455,
614 + 0.03417291150313457,
615 + 0.0059635515381250915,
616 + 0.006146668610584633,
617 + 0.195202799241872,
618 + 0.002774748505613063,
619 + 0.004715556203528212,
620 + 0.0044776206444088066,
621 + 0.11205481848665985,
622 + 0.005654468581425864,
623 + 0.0028820527773727946,
624 + 0.07383000437381543,
625 + 0.005516839189386207,
626 + 0.006496573844583759,
627 + 0.09843067502551392,
628 + 0.0027140982650532145,
629 + 0.0006893133109782768,
630 + 0.08425368129464937,
631 + 0.021325557661466685,
632 + 0.006493074792243767,
633 + 0.07023414491908442,
634 + 0.002077270739174807,
635 + 0.0024633328473538415,
636 + 0.0007744569179180639,
637 + 0.015413325557661468,
638 + 0.0011990086018370024,
639 + 0.13162851727657093,
640 + 0.10115993585070711,
641 + 0.0026989357049132527,
642 + 0.03319317684793702,
643 + 0.002946202070272634,
644 + 0.0783216212275842,
645 + 0.0018358361277154103,
646 + 0.00258813238081353,
647 + 0.2141688292754046,
648 + 0.09853681294649366,
649 + 0.0032482869222918796,
650 + 0.04359352675317102,
651 + 0.01993526753171016,
652 + 0.0036880011663507797,
653 + 0.008011663507799971,
654 + 0.12014696019827964,
655 + 0.0029846916460125384,
656 + 0.0017553579238956116,
657 + 0.029470185158186325,
658 + 0.010413179763813967,
659 + 0.030699518880303252,
660 + 0.03508499781309229,
661 + 0.002021285901734947,
662 + 0.0010613792097973467,
663 + 0.0005295232541186761,
664 + 0.009677212421635807,
665 + 0.010585799679253535,
666 + 0.17101734946785244,
667 + 0.07968625164018078,
668 + 0.007839043592360402,
669 + 0.005438693687126403,
670 + 0.0183606939787141,
671 + 0.2732701559994168,
672 + 0.004953491762647616,
673 + 0.007259367254701851,
674 + 0.008104971570199739,
675 + 0.13274588132380813,
676 + 0.004210526315789474,
677 + 0.004997813092287506,
678 + 0.017006560723137484,
679 + 0.007442484327161393,
680 + 0.016789619478058026,
681 + 0.08477737279486806,
682 + 0.005106283714827234,
683 + 0.0005026971861787433,
684 + 0.04040355736987899,
685 + 0.037535500801866156,
686 + 0.00885960052485785,
687 + 0.0336410555474559,
688 + 0.007066919376002332,
689 + 0.005344219273946639,
690 + 0.0006333284735384167,
691 + 0.010684939495553289,
692 + 0.0063064586674442345,
693 + 0.15386849394955532,
694 + 0.015049424114302375,
695 + 0.012162705933809595,
696 + 0.020425134859308938,
697 + 0.037366379938766583,
698 + 0.02157165767604607,
699 + 0.009373961218836564,
700 + 0.0173214754337367,
701 + 0.009616562181075958,
702 + 0.029522670943286193,
703 + 0.010154249890654615,
704 + 0.018600962239393497,
705 + 0.06362210234728094,
706 + 0.03157078291296107,
707 + 0.151603440734801,
708 + 0.0062329785683044175,
709 + 0.014775331681003062,
710 + 0.0020854351946347867,
711 + 0.1826342032366234,
712 + 0.0878017203674005,
713 + 0.054190989940224525,
714 + 0.010329202507654177,
715 + 0.012763376585508092,
716 + 0.0064872430383437815,
717 + 0.006381105117364048,
718 + 0.005388540603586529,
719 + 0.0090800408222773,
720 + 0.09611196967487973,
721 + 0.09940691062837148,
722 + 0.01033969966467415,
723 + 0.004034407348009914,
724 + 0.008826942703017933,
725 + 0.11474675608689314,
726 + 0.07132584924916169,
727 + 0.012388977985129028,
728 + 0.005435194634786413,
729 + 0.1417174515235457,
730 + 0.0037066627788307337,
731 + 0.0045802595130485495,
732 + 0.060800699810468,
733 + 0.005341886572386646,
734 + 0.005683627350925791,
735 + 0.12434932205860913,
736 + 0.004596588423968508,
737 + 0.0007534626038781163,
738 + 0.07107041842834232,
739 + 0.022361277154104096,
740 + 0.04784720804782038,
741 + 0.06277533168100306,
742 + 0.003441901151771395,
743 + 0.005828254847645429,
744 + 0.0009669047966175828,
745 + 0.009470768333576322,
746 + 0.002077270739174807,
747 + 0.12797667298440007,
748 + 0.08797783933518005,
749 + 0.005388540603586529,
750 + 0.0024913252660737715,
751 + 0.007550954949701123,
752 + 0.2786866890217233,
753 + 0.002509986878553725,
754 + 0.029002478495407494,
755 + 0.0303204548768042,
756 + 0.07576614666861058,
757 + 0.00246799825047383,
758 + 0.00592389561160519,
759 + 0.039574281965301064,
760 + 0.00706808572678233,
761 + 0.03304505029887739,
762 + 0.05474150750838315,
763 + 0.0028633911648928414,
764 + 0.0005073625892987316,
765 + 0.07293541332555767,
766 + 0.053528502697186175,
767 + 0.022566554891383584,
768 + 0.038151334013704616,
769 + 0.002716430966613209,
770 + 0.005049132526607377,
771 + 0.0009902318122175246,
772 + 0.008997229916897508,
773 + 0.0011861787432570347,
774 + 0.1666377022889634,
775 + 0.14414462749671964,
776 + 0.003374252806531564,
777 + 0.005169266656947077,
778 + 0.008468873013558828,
779 + 0.16337541915731155,
780 + 0.002873888321912815,
781 + 0.004305000728969237,
782 + 0.0031141565825922144,
783 + 0.1241172182533897,
784 + 0.0052800699810468,
785 + 0.008969237498177577,
786 + 0.024094474413179766,
787 + 0.017029887738737422,
788 + 0.01722700102055693,
789 + 0.10618457501093455,
790 + 0.006147834961364631,
791 + 0.0008269427030179326,
792 + 0.03303571949263741,
793 + 0.024188948826359528,
794 + 0.05213937891820965,
795 + 0.04505846333284735,
796 + 0.0035270447587111824,
797 + 0.006799825047383001,
798 + 0.0008199445983379502,
799 + 0.02206735675754483,
800 + 0.001010059775477475,
801 + 0.11971191135734072,
802 + 0.04656538854060359,
803 + 0.011243621519171892,
804 + 0.06513019390581717,
805 + 0.032375564951159064,
806 + 0.06347047674588133,
807 + 0.013678961947805804,
808 + 0.03309870243475726,
809 + 0.006982942119842543,
810 + 0.009726199154395685,
811 + 0.010121592068814697,
812 + 0.032514360693978714,
813 + 0.04986032949409535,
814 + 0.039734072022160664,
815 + 0.15690683773144773,
816 + 0.03949963551538125,
817 + 0.014790494241143023,
818 + 0.002722262720513194,
819 + 0.02614375273363464,
820 + 0.10753637556495116,
821 + 0.06764834523983088,
822 + 0.006221315060504448,
823 + 0.021317393206006705,
824 + 0.0030826651115322934,
825 + 0.002399183554454002,
826 + 0.0019069835252952323,
827 + 0.015595276279341012,
828 + 0.0925126111678087,
829 + 0.18437906400349907,
830 + 0.006538562472663654,
831 + 0.008719638431258201,
832 + 0.02116693395538708,
833 + 0.18241376293920394,
834 + 0.007290858725761773,
835 + 0.005976381396705059,
836 + 0.005629975215045925,
837 + 0.09721300481119698,
838 + 0.004810030616707975,
839 + 0.024303251202799244,
840 + 0.012954658113427612,
841 + 0.011057005394372358,
842 + 0.02733459688001166,
843 + 0.10135121737862662,
844 + 0.012016912086309959,
845 + 0.001055547455897361,
846 + 0.009027555037177431,
847 + 0.07162326869806095,
848 + 0.01007143898527482,
849 + 0.07297623560285756,
850 + 0.006741507508383147,
851 + 0.0036891675171307776,
852 + 0.0008409389123778977,
853 + 0.011272780288671819,
854 + 0.007020265344802449,
855 + 0.1030389269572824,
856 + 0.15350809155853623,
857 + 0.004232686980609419,
858 + 0.004353987461729115,
859 + 0.0023385333138941536,
860 + 0.14450386353695874,
861 + 0.002546143752733635,
862 + 0.0024470039364338824,
863 + 0.01200758128006998,
864 + 0.0981227584195947,
865 + 0.003161976964572095,
866 + 0.040695145064878264,
867 + 0.03460446129173349,
868 + 0.003908441463770229,
869 + 0.01598483743986004,
870 + 0.13107216795451232,
871 + 0.003129319142732177,
872 + 0.00032307916605919226,
873 + 0.04050386353695874,
874 + 0.05452689896486368,
875 + 0.03589677795597026,
876 + 0.07087097244496282,
877 + 0.006143169558244642,
878 + 0.008684647907858289,
879 + 0.0004607085580988482,
880 + 0.022010205569324977,
881 + 0.0009097536083977258,
882 + 0.07328765126111678,
883 + 0.14751421490013122,
884 + 0.008015162560139961,
885 + 0.006601545414783497,
886 + 0.025279486805656802,
887 + 0.1682449336637994,
888 + 0.008313748359819215,
889 + 0.007010934538562473,
890 + 0.005886572386645284,
891 + 0.16889575739903775,
892 + 0.004123050007289692,
893 + 0.011925936725470185,
894 + 0.10007289692374982,
895 + 0.013380376148126549,
896 + 0.009021723283277445,
897 + 0.08650823735238372,
898 + 0.007756232686980609,
899 + 0.0007243038343781893,
900 + 0.0026791077416533026,
901 + 0.02797492345823006,
902 + 0.032384895757399036,
903 + 0.04187432570345531,
904 + 0.00882461000145794,
905 + 0.0032401224668318998,
906 + 0.00033357632307916605,
907 + 0.027878116343490307,
908 + 0.0022277299897944304,
909 + 0.14333518005540166,
910 + 0.1725534334451086,
911 + 0.02781629975215046,
912 + 0.006909462020702727,
913 + 0.005264907420906838,
914 + 0.16661437527336345,
915 + 0.004325995043009185,
916 + 0.003334596880011664,
917 + 0.005312727802886718,
918 + 0.14024668318996938,
919 + 0.0013261408368566844,
920 + 0.003504884093891238,
921 + 0.006375273363464061,
922 + 0.04964922000291588,
923 + 0.008290421344219274,
924 + 0.09536783787724158,
925 + 0.05394372357486515,
926 + 0.005505175681586237,
927 + 0.005339553870826651,
928 + 0.01782067356757545,
929 + 0.006710016037323225,
930 + 0.05105933809593235,
931 + 0.002983525295232541,
932 + 0.002940370316372649,
933 + 0.0004548768041988629,
934 + 0.01208456043154979,
935 + 0.000915585362297711,
936 + 0.20146260387811635,
937 + 0.067196967487972,
938 + 0.006158332118384605,
939 + 0.025438110511736407,
940 + 0.07753783350342616,
941 + 0.1273876658405015,
942 + 0.009337804344656656,
943 + 0.07683452398308792,
944 + 0.0070412596588423975,
945 + 0.08747164309666132,
946 + 0.0038827817466102928,
947 + 0.018116926665694706,
948 + 0.005017641055547455,
949 + 0.004567429654468581,
950 + 0.028277008310249308,
951 + 0.05271555620352821,
952 + 0.004394809739029013,
953 + 0.0013343052923166642,
954 + 0.00411605190260971,
955 + 0.059621519171890944,
956 + 0.09073859163143316,
957 + 0.01446858142586383,
958 + 0.006770666277883074,
959 + 0.003425572240851436,
960 + 0.0004455459979588861,
961 + 0.010401516256013998,
962 + 0.005825922146085436,
963 + 0.10833882490158916,
964 + 0.007584779122321038,
965 + 0.016903921854497742,
966 + 0.02719580113719201,
967 + 0.0304814112844438,
968 + 0.02206385770520484,
969 + 0.013064295086747339,
970 + 0.02696369733197259,
971 + 0.009581571657676046,
972 + 0.026761918647033093,
973 + 0.006510570053943724,
974 + 0.021941390873305145,
975 + 0.07042659279778393,
976 + 0.05437410701268406,
977 + 0.1425175681586237,
978 + 0.027802303542790494,
979 + 0.037690625455605774,
980 + 0.0019606356611750987,
981 + 0.1095623268698061,
982 + 0.06157748942994606,
983 + 0.044618749088788455,
984 + 0.04955124653739612,
985 + 0.03608689313310978,
986 + 0.018381688292754043,
987 + 0.003404577926811489,
988 + 0.015036594255722409,
989 + 0.009600233270156,
990 + 0.10794693103951014,
991 + 0.12447528794284882,
992 + 0.0031981338387520046,
993 + 0.0074716430966613205,
994 + 0.003202799241871993,
995 + 0.13437643971424407,
996 + 0.006655197550663361,
997 + 0.0036693395538708266,
998 + 0.049338970695436656,
999 + 0.09486863974340283,
1000 + 0.0015990669193760023,
1001 + 0.0026604461291733486,
1002 + 0.051775477474850555,
1003 + 0.0041347135150896636,
1004 + 0.005450357194926374,
1005 + 0.12030325120279925,
1006 + 0.04581309228750547,
1007 + 0.0004537104534188657,
1008 + 0.12425601399620935,
1009 + 0.025981629975215047,
1010 + 0.023926519900860182,
1011 + 0.04423385333138941,
1012 + 0.0017950138504155123,
1013 + 0.002661612479953346,
1014 + 0.0006333284735384167,
1015 + 0.008449045050298877,
1016 + 0.000653156436798367,
1017 + 0.04816678816153958,
1018 + 0.008625164018078437,
1019 + 0.0039037760606502403,
1020 + 0.005228750546726928,
1021 + 0.004531272780288672,
1022 + 0.0056672984400058316,
1023 + 0.00359585945473101,
1024 + 0.0032179618020119548,
1025 + 0.0038093016474704767,
1026 + 0.011452398308791368,
1027 + 0.002519317684793702,
1028 + 0.00280390727511299,
1029 + 0.005572824026826068,
1030 + 0.004554599795888614,
1031 + 0.004531272780288672,
1032 + 0.0035841959469310393,
1033 + 0.004400641492928998,
1034 + 0.0036670068523108326,
1035 + 0.004839189386207902,
1036 + 0.006258638285464354,
1037 + 0.004897506925207757,
1038 + 0.840776789619478,
1039 + 0.004968654322787578,
1040 + 0.002886718180492783,
1041 + 0.0019757982213150604,
1042 + 0.0018568304417553576,
1043 + 0.001691208630995772,
1044 + 0.09009243329931477,
1045 + 0.14030150167662925,
1046 + 0.013242746756086894,
1047 + 0.013746610293045632,
1048 + 0.027342761335471644,
1049 + 0.16938912377897652,
1050 + 0.006607377168683481,
1051 + 0.01661933226417845,
1052 + 0.008173786266219566,
1053 + 0.13297448607668758,
1054 + 0.0034675608689313307,
1055 + 0.016641492928998396,
1056 + 0.011722991689750693,
1057 + 0.021493512173786266,
1058 + 0.03430820819361423,
1059 + 0.10099548039072752,
1060 + 0.00873596734217816,
1061 + 0.0018323370753754193,
1062 + 0.020103222044029742,
1063 + 0.047197550663362,
1064 + 0.040833940807697915,
1065 + 0.03361189677795597,
1066 + 0.010844729552412887,
1067 + 0.005544831608106138,
1068 + 0.0007522962530981193,
1069 + 0.01525120279924187,
1070 + 0.00815512465373961,
1071 + 0.2109648636827526,
1072 + 0.058258055110074355,
1073 + 0.007181221752442048,
1074 + 0.043560868931331105,
1075 + 0.004058900714389853,
1076 + 0.10618107595859454,
1077 + 0.0062399766729844,
1078 + 0.004835690333867911,
1079 + 0.02679224376731302,
1080 + 0.08414637702288964,
1081 + 0.0030698352529523252,
1082 + 0.03637498177576906,
1083 + 0.01592885260242018,
1084 + 0.017413617145356466,
1085 + 0.008430383437818923,
1086 + 0.037231083248286924,
1087 + 0.03290275550371775,
1088 + 0.007538125091121154,
1089 + 0.004500947660008748,
1090 + 0.05932409972299169,
1091 + 0.16006764834523984,
1092 + 0.03309636973319726,
1093 + 0.007766729844000583,
1094 + 0.005225251494386936,
1095 + 0.0006321621227584196,
1096 + 0.012989648636827526,
1097 + 0.005274238227146815,
1098 + 0.1254503571949264,
1099 + 0.12852719055255868,
1100 + 0.0035433736696311416,
1101 + 0.005203090829566993,
1102 + 0.0019314768916751715,
1103 + 0.20520775623268697,
1104 + 0.002509986878553725,
1105 + 0.00343606939787141,
1106 + 0.027138649948972155,
1107 + 0.13926578218399185,
1108 + 0.004565096952908587,
1109 + 0.005614812654905963,
1110 + 0.00874413179763814,
1111 + 0.004109053797929727,
1112 + 0.008300918501239247,
1113 + 0.08270943286193323,
1114 + 0.002912377897652719,
1115 + 0.0037066627788307337,
1116 + 0.06909578655780726,
1117 + 0.03242805073625893,
1118 + 0.05237614812654906,
1119 + 0.04723487388832191,
1120 + 0.0038991106575302524,
1121 + 0.006299460562764251,
1122 + 0.00043388249015891526,
1123 + 0.020029741944889927,
1124 + 0.005311561452106721,
1125 + 0.09334072022160665,
1126 + 0.022940953491762648,
1127 + 0.024658988190698353,
1128 + 0.02901297565242747,
1129 + 0.03531593526753171,
1130 + 0.0758023035427905,
1131 + 0.013711619769645722,
1132 + 0.021597317393206007,
1133 + 0.009670214316955824,
1134 + 0.044728386062108175,
1135 + 0.010596296836273509,
1136 + 0.03264382563055839,
1137 + 0.0604822860475288,
1138 + 0.05489546581134276,
1139 + 0.11501851581863246,
1140 + 0.01837585653885406,
1141 + 0.026237060796034405,
1142 + 0.0011255285026971862,
1143 + 0.08704125965884241,
1144 + 0.10156349322058608,
1145 + 0.06660562764251349,
1146 + 0.023434319871701415,
1147 + 0.010777081207173057,
1148 + 0.005409534917626476,
1149 + 0.003123487388832191,
1150 + 0.0028762210234728096,
1151 + 0.0089995626184575,
1152 + 0.07518297127861205,
1153 + 0.2314868056568013,
1154 + 0.002226563639014434,
1155 + 0.003285610147251786,
1156 + 0.0027455897361131363,
1157 + 0.2724537104534189,
1158 + 0.0016655489138358362,
1159 + 0.0019209797346551977,
1160 + 0.0022137337804344656,
1161 + 0.17690392185449774,
1162 + 0.0014532730718763668,
1163 + 0.0024994897215337513,
1164 + 0.015302522233561744,
1165 + 0.003441901151771395,
1166 + 0.015303688584341741,
1167 + 0.09314593964134713,
1168 + 0.0017833503426155418,
1169 + 0.0005108616416387229,
1170 + 0.017828838023035427,
1171 + 0.010385187345094037,
1172 + 0.003168975069252078,
1173 + 0.01902901297565243,
1174 + 0.005525003644846187,
1175 + 0.0010088934246974776,
1176 + 0.0009272488700976819,
1177 + 0.036282840064149294,
1178 + 0.0022977110365942554,
1179 + 0.0766805656801283,
1180 + 0.22270418428342326,
1181 + 0.005283569033386791,
1182 + 0.007155562035282111,
1183 + 0.01173582154833066,
1184 + 0.1715620352821111,
1185 + 0.003925936725470185,
1186 + 0.004425134859308937,
1187 + 0.020040239101909902,
1188 + 0.14243242455168392,
1189 + 0.0016737133692958156,
1190 + 0.0066808572678232975,
1191 + 0.011980755212130047,
1192 + 0.012638577052048404,
1193 + 0.07206065024055984,
1194 + 0.08115701997375711,
1195 + 0.00710424260096224,
1196 + 0.0007278028867181805,
1197 + 0.02347630849978131,
1198 + 0.04595538708266512,
1199 + 0.01481965301064295,
1200 + 0.013925061962385188,
1201 + 0.0018125091121154687,
1202 + 0.00529173348884677,
1203 + 0.0016340574427759146,
1204 + 0.03072401224668319,
1205 + 0.0023746901880740633,
1206 + 0.25174165330223064,
1207 + 0.06673392622831317,
1208 + 0.00878378772415804,
1209 + 0.03956261845750109,
1210 + 0.010077270739174807,
1211 + 0.0844787869951888,
1212 + 0.00985216503863537,
1213 + 0.004973319725907567,
1214 + 0.01893220586091267,
1215 + 0.11200583175389998,
1216 + 0.0028715556203528212,
1217 + 0.004095057588569762,
1218 + 0.01202391019098994,
1219 + 0.01756757544831608,
1220 + 0.014825484764542934,
1221 + 0.05312961073042717,
1222 + 0.06746872721971132,
1223 + 0.003845458521650386,
1224 + 0.0210806239976673,
1225 + 0.019443067502551394,
1226 + 0.08017028721387957,
1227 + 0.01825572240851436,
1228 + 0.005365213587986587,
1229 + 0.01959702580551101,
1230 + 0.026184575010934536,
1231 + 0.02474879720075813,
1232 + 0.002171745152354571,
1233 + 0.25827321767021433,
1234 + 0.048050153083539875,
1235 + 0.01043184137629392,
1236 + 0.03930485493512174,
1237 + 0.027640180784370902,
1238 + 0.03294007872867765,
1239 + 0.006474413179763814,
1240 + 0.018314039947514214,
1241 + 0.015119405161102202,
1242 + 0.014706516984983233,
1243 + 0.005494678524566263,
1244 + 0.03309870243475726,
1245 + 0.043864120134130345,
1246 + 0.058996355153812505,
1247 + 0.06265986295378335,
1248 + 0.04633328473538417,
1249 + 0.03790756670068523,
1250 + 0.0004642076104388394,
1251 + 0.037849249161685375,
1252 + 0.08369966467415076,
1253 + 0.04999679253535501,
1254 + 0.02392768625164018,
1255 + 0.010998687855372504,
1256 + 0.009881323808135296,
1257 + 0.003867619186470331,
1258 + 0.012434465665548913,
1259 + 0.007253535500801866,
1260 + 0.11106225397288234,
1261 + 0.17624726636535937,
1262 + 0.008209943140399476,
1263 + 0.008390727511299025,
1264 + 0.012682898381688294,
1265 + 0.1825653885406036,
1266 + 0.001538416678816154,
1267 + 0.004590756670068524,
1268 + 0.008710307625018223,
1269 + 0.1299513048549351,
1270 + 0.002677941390873305,
1271 + 0.012309666132089225,
1272 + 0.014087184720804781,
1273 + 0.01199941682461,
1274 + 0.031246537396121883,
1275 + 0.07206648199445984,
1276 + 0.008254264470039366,
1277 + 0.0007033095203382417,
1278 + 0.007034261554162415,
1279 + 0.006599212713223502,
1280 + 0.013906400349905234,
1281 + 0.050098265053214755,
1282 + 0.007133401370462167,
1283 + 0.017750692520775622,
1284 + 0.0008257763522379356,
1285 + 0.03918821985712203,
1286 + 0.06015454147834961,
1287 + );
1288 +}