3v4l.org

run code in 300+ PHP versions simultaneously
<?php /** * Class OneFileLoginApplication * * An entire php application with user registration, login and logout in one file. * Uses very modern password hashing via the PHP 5.5 password hashing functions. * This project includes a compatibility file to make these functions available in PHP 5.3.7+ and PHP 5.4+. * * @author Panique * @link https://github.com/panique/php-login-one-file/ * @license http://opensource.org/licenses/MIT MIT License */ class OneFileLoginApplication { /** * @var string Type of used database (currently only SQLite, but feel free to expand this with mysql etc) */ private $db_type = "sqlite"; // /** * @var string Path of the database file (create this with _install.php) */ private $db_sqlite_path = "./users.db"; /** * @var object Database connection */ private $db_connection = null; /** * @var bool Login status of user */ private $user_is_logged_in = false; /** * @var string System messages, likes errors, notices, etc. */ public $feedback = ""; /** * Does necessary checks for PHP version and PHP password compatibility library and runs the application */ public function __construct() { if ($this->performMinimumRequirementsCheck()) { $this->runApplication(); } } /** * Performs a check for minimum requirements to run this application. * Does not run the further application when PHP version is lower than 5.3.7 * Does include the PHP password compatibility library when PHP version lower than 5.5.0 * (this library adds the PHP 5.5 password hashing functions to older versions of PHP) * @return bool Success status of minimum requirements check, default is false */ private function performMinimumRequirementsCheck() { if (version_compare(PHP_VERSION, '5.3.7', '<')) { echo "Sorry, Simple PHP Login does not run on a PHP version older than 5.3.7 !"; } elseif (version_compare(PHP_VERSION, '5.5.0', '<')) { require_once("libraries/password_compatibility_library.php"); return true; } elseif (version_compare(PHP_VERSION, '5.5.0', '>=')) { return true; } // default return return false; } /** * This is basically the controller that handles the entire flow of the application. */ public function runApplication() { // check is user wants to see register page (etc.) if (isset($_GET["action"]) && $_GET["action"] == "register") { $this->doRegistration(); $this->showPageRegistration(); } else { // start the session, always needed! $this->doStartSession(); // check for possible user interactions (login with session/post data or logout) $this->performUserLoginAction(); // show "page", according to user's login status if ($this->getUserLoginStatus()) { $this->showPageLoggedIn(); } else { $this->showPageLoginForm(); } } } /** * Creates a PDO database connection (in this case to a SQLite flat-file database) * @return bool Database creation success status, false by default */ private function createDatabaseConnection() { try { $this->db_connection = new PDO($this->db_type . ':' . $this->db_sqlite_path); return true; } catch (PDOException $e) { $this->feedback = "PDO database connection problem: " . $e->getMessage(); } catch (Exception $e) { $this->feedback = "General problem: " . $e->getMessage(); } return false; } /** * Handles the flow of the login/logout process. According to the circumstances, a logout, a login with session * data or a login with post data will be performed */ private function performUserLoginAction() { if (isset($_GET["action"]) && $_GET["action"] == "logout") { $this->doLogout(); } elseif (!empty($_SESSION['user_name']) && ($_SESSION['user_is_logged_in'])) { $this->doLoginWithSessionData(); } elseif (isset($_POST["login"])) { $this->doLoginWithPostData(); } } /** * Simply starts the session. * It's cleaner to put this into a method than writing it directly into runApplication() */ private function doStartSession() { session_start(); } /** * Set a marker (NOTE: is this method necessary ?) */ private function doLoginWithSessionData() { $this->user_is_logged_in = true; // ? } /** * Process flow of login with POST data */ private function doLoginWithPostData() { if ($this->checkLoginFormDataNotEmpty()) { if ($this->createDatabaseConnection()) { $this->checkPasswordCorrectnessAndLogin(); } } } /** * Logs the user out */ private function doLogout() { $_SESSION = array(); session_destroy(); $this->user_is_logged_in = false; $this->feedback = "You were just logged out."; } /** * The registration flow * @return bool */ private function doRegistration() { if ($this->checkRegistrationData()) { if ($this->createDatabaseConnection()) { $this->createNewUser(); } } // default return return false; } /** * Validates the login form data, checks if username and password are provided * @return bool Login form data check success state */ private function checkLoginFormDataNotEmpty() { if (!empty($_POST['user_name']) && !empty($_POST['user_password'])) { return true; } elseif (empty($_POST['user_name'])) { $this->feedback = "Username field was empty."; } elseif (empty($_POST['user_password'])) { $this->feedback = "Password field was empty."; } // default return return false; } /** * Checks if user exits, if so: check if provided password matches the one in the database * @return bool User login success status */ private function checkPasswordCorrectnessAndLogin() { // remember: the user can log in with username or email address $sql = 'SELECT user_name, user_email, user_password_hash FROM users WHERE user_name = :user_name OR user_email = :user_name LIMIT 1'; $query = $this->db_connection->prepare($sql); $query->bindValue(':user_name', $_POST['user_name']); $query->execute(); // Btw that's the weird way to get num_rows in PDO with SQLite: // if (count($query->fetchAll(PDO::FETCH_NUM)) == 1) { // Holy! But that's how it is. $result->numRows() works with SQLite pure, but not with SQLite PDO. // This is so crappy, but that's how PDO works. // As there is no numRows() in SQLite/PDO (!!) we have to do it this way: // If you meet the inventor of PDO, punch him. Seriously. $result_row = $query->fetchObject(); if ($result_row) { // using PHP 5.5's password_verify() function to check password if (password_verify($_POST['user_password'], $result_row->user_password_hash)) { // write user data into PHP SESSION [a file on your server] $_SESSION['user_name'] = $result_row->user_name; $_SESSION['user_email'] = $result_row->user_email; $_SESSION['user_is_logged_in'] = true; $this->user_is_logged_in = true; return true; } else { $this->feedback = "Wrong password."; } } else { $this->feedback = "This user does not exist."; } // default return return false; } /** * Validates the user's registration input * @return bool Success status of user's registration data validation */ private function checkRegistrationData() { // if no registration form submitted: exit the method if (!isset($_POST["register"])) { return false; } // validating the input if (!empty($_POST['user_name']) && strlen($_POST['user_name']) <= 64 && strlen($_POST['user_name']) >= 2 && preg_match('/^[a-z\d]{2,64}$/i', $_POST['user_name']) && !empty($_POST['user_email']) && strlen($_POST['user_email']) <= 64 && filter_var($_POST['user_email'], FILTER_VALIDATE_EMAIL) && !empty($_POST['user_password_new']) && !empty($_POST['user_password_repeat']) && ($_POST['user_password_new'] === $_POST['user_password_repeat']) ) { // only this case return true, only this case is valid return true; } elseif (empty($_POST['user_name'])) { $this->feedback = "Empty Username"; } elseif (empty($_POST['user_password_new']) || empty($_POST['user_password_repeat'])) { $this->feedback = "Empty Password"; } elseif ($_POST['user_password_new'] !== $_POST['user_password_repeat']) { $this->feedback = "Password and password repeat are not the same"; } elseif (strlen($_POST['user_password_new']) < 6) { $this->feedback = "Password has a minimum length of 6 characters"; } elseif (strlen($_POST['user_name']) > 64 || strlen($_POST['user_name']) < 2) { $this->feedback = "Username cannot be shorter than 2 or longer than 64 characters"; } elseif (!preg_match('/^[a-z\d]{2,64}$/i', $_POST['user_name'])) { $this->feedback = "Username does not fit the name scheme: only a-Z and numbers are allowed, 2 to 64 characters"; } elseif (empty($_POST['user_email'])) { $this->feedback = "Email cannot be empty"; } elseif (strlen($_POST['user_email']) > 64) { $this->feedback = "Email cannot be longer than 64 characters"; } elseif (!filter_var($_POST['user_email'], FILTER_VALIDATE_EMAIL)) { $this->feedback = "Your email address is not in a valid email format"; } else { $this->feedback = "An unknown error occurred."; } // default return return false; } /** * Creates a new user. * @return bool Success status of user registration */ private function createNewUser() { // remove html code etc. from username and email $user_name = htmlentities($_POST['user_name'], ENT_QUOTES); $user_email = htmlentities($_POST['user_email'], ENT_QUOTES); $user_password = $_POST['user_password_new']; // crypt the user's password with the PHP 5.5's password_hash() function, results in a 60 char hash string. // the constant PASSWORD_DEFAULT comes from PHP 5.5 or the password_compatibility_library $user_password_hash = password_hash($user_password, PASSWORD_DEFAULT); $sql = 'SELECT * FROM users WHERE user_name = :user_name OR user_email = :user_email'; $query = $this->db_connection->prepare($sql); $query->bindValue(':user_name', $user_name); $query->bindValue(':user_email', $user_email); $query->execute(); // As there is no numRows() in SQLite/PDO (!!) we have to do it this way: // If you meet the inventor of PDO, punch him. Seriously. $result_row = $query->fetchObject(); if ($result_row) { $this->feedback = "Sorry, that username / email is already taken. Please choose another one."; } else { $sql = 'INSERT INTO users (user_name, user_password_hash, user_email) VALUES(:user_name, :user_password_hash, :user_email)'; $query = $this->db_connection->prepare($sql); $query->bindValue(':user_name', $user_name); $query->bindValue(':user_password_hash', $user_password_hash); $query->bindValue(':user_email', $user_email); // PDO's execute() gives back TRUE when successful, FALSE when not // @link http://stackoverflow.com/q/1661863/1114320 $registration_success_state = $query->execute(); if ($registration_success_state) { $this->feedback = "Your account has been created successfully. You can now log in."; return true; } else { $this->feedback = "Sorry, your registration failed. Please go back and try again."; } } // default return return false; } /** * Simply returns the current status of the user's login * @return bool User's login status */ public function getUserLoginStatus() { return $this->user_is_logged_in; } /** * Simple demo-"page" that will be shown when the user is logged in. * In a real application you would probably include an html-template here, but for this extremely simple * demo the "echo" statements are totally okay. */ private function showPageLoggedIn() { if ($this->feedback) { echo $this->feedback . "<br/><br/>"; } echo 'Hello ' . $_SESSION['user_name'] . ', you are logged in.<br/><br/>'; echo '<a href="' . $_SERVER['SCRIPT_NAME'] . '?action=logout">Log out</a>'; } /** * Simple demo-"page" with the login form. * In a real application you would probably include an html-template here, but for this extremely simple * demo the "echo" statements are totally okay. */ private function showPageLoginForm() { if ($this->feedback) { echo $this->feedback . "<br/><br/>"; } echo '<h2>Login</h2>'; echo '<form method="post" action="' . $_SERVER['SCRIPT_NAME'] . '" name="loginform">'; echo '<label for="login_input_username">Username (or email)</label> '; echo '<input id="login_input_username" type="text" name="user_name" required /> '; echo '<label for="login_input_password">Password</label> '; echo '<input id="login_input_password" type="password" name="user_password" required /> '; echo '<input type="submit" name="login" value="Log in" />'; echo '</form>'; echo '<a href="' . $_SERVER['SCRIPT_NAME'] . '?action=register">Register new account</a>'; } /** * Simple demo-"page" with the registration form. * In a real application you would probably include an html-template here, but for this extremely simple * demo the "echo" statements are totally okay. */ private function showPageRegistration() { if ($this->feedback) { echo $this->feedback . "<br/><br/>"; } echo '<h2>Registration</h2>'; echo '<form method="post" action="' . $_SERVER['SCRIPT_NAME'] . '?action=register" name="registerform">'; echo '<label for="login_input_username">Username (only letters and numbers, 2 to 64 characters)</label>'; echo '<input id="login_input_username" type="text" pattern="[a-zA-Z0-9]{2,64}" name="user_name" required />'; echo '<label for="login_input_email">User\'s email</label>'; echo '<input id="login_input_email" type="email" name="user_email" required />'; echo '<label for="login_input_password_new">Password (min. 6 characters)</label>'; echo '<input id="login_input_password_new" class="login_input" type="password" name="user_password_new" pattern=".{6,}" required autocomplete="off" />'; echo '<label for="login_input_password_repeat">Repeat password</label>'; echo '<input id="login_input_password_repeat" class="login_input" type="password" name="user_password_repeat" pattern=".{6,}" required autocomplete="off" />'; echo '<input type="submit" name="register" value="Register" />'; echo '</form>'; echo '<a href="' . $_SERVER['SCRIPT_NAME'] . '">Homepage</a>'; } } // run the application $application = new OneFileLoginApplication();

Here you find the average performance (time & memory) of each version. A grayed out version indicates it didn't complete successfully (based on exit-code).

VersionSystem time (s)User time (s)Memory (MiB)
8.3.60.0180.00418.38
8.3.50.0110.00822.12
8.3.40.0160.00318.92
8.3.30.0110.00319.26
8.3.20.0050.00220.54
8.3.10.0050.00321.96
8.3.00.0040.00422.57
8.2.180.0100.01325.92
8.2.170.0120.00619.04
8.2.160.0080.00322.96
8.2.150.0000.00925.66
8.2.140.0040.00424.66
8.2.130.0080.00026.16
8.2.120.0090.00019.89
8.2.110.0030.00622.14
8.2.100.0090.00319.69
8.2.90.0000.00819.34
8.2.80.0040.00418.18
8.2.70.0320.00617.88
8.2.60.0060.00318.05
8.2.50.0040.00418.07
8.2.40.0040.00418.39
8.2.30.0000.00718.18
8.2.20.0000.00917.90
8.2.10.0060.00317.93
8.2.00.0040.00417.99
8.1.280.0120.00325.92
8.1.270.0040.00424.66
8.1.260.0040.00426.35
8.1.250.0080.00028.09
8.1.240.0090.00023.95
8.1.230.0030.00919.34
8.1.220.0040.00417.91
8.1.210.0030.00618.77
8.1.200.0070.00317.48
8.1.190.0090.00017.78
8.1.180.0080.00018.10
8.1.170.0000.00918.82
8.1.160.0080.00022.09
8.1.150.0090.00018.81
8.1.140.0060.00317.64
8.1.130.0040.00417.92
8.1.120.0000.00717.59
8.1.110.0090.00317.52
8.1.100.0020.00517.50
8.1.90.0040.00417.46
8.1.80.0000.00717.49
8.1.70.0040.00417.54
8.1.60.0000.00917.72
8.1.50.0080.00017.62
8.1.40.0000.00917.51
8.1.30.0030.00617.71
8.1.20.0060.00317.80
8.1.10.0040.00417.59
8.1.00.0030.00717.64
8.0.300.0040.00418.77
8.0.290.0040.00417.30
8.0.280.0070.00018.54
8.0.270.0040.00417.36
8.0.260.0000.00717.00
8.0.250.0030.00617.07
8.0.240.0000.00817.05
8.0.230.0070.00016.98
8.0.220.0070.00016.98
8.0.210.0030.00316.91
8.0.200.0040.00417.04
8.0.190.0040.00417.01
8.0.180.0000.00816.95
8.0.170.0050.00516.94
8.0.160.0050.00316.97
8.0.150.0040.00416.98
8.0.140.0000.00816.95
8.0.130.0000.00613.50
8.0.120.0000.00816.87
8.0.110.0050.00216.96
8.0.100.0000.00716.90
8.0.90.0040.00416.89
8.0.80.0120.00617.03
8.0.70.0050.00316.92
8.0.60.0040.00417.00
8.0.50.0000.00816.89
8.0.30.0090.01217.31
8.0.20.0150.00717.40
8.0.10.0000.00817.09
8.0.00.0050.01216.68
7.4.330.0000.00615.01
7.4.320.0040.00416.69
7.4.300.0030.00316.77
7.4.290.0000.00716.73
7.4.280.0050.00316.48
7.4.270.0000.00716.64
7.4.260.0030.00316.60
7.4.250.0050.00316.68
7.4.240.0080.00016.62
7.4.230.0000.00816.47
7.4.220.0100.02316.74
7.4.210.0060.00916.77
7.4.200.0040.00416.48
7.4.190.0000.00816.82
7.4.160.0080.00816.64
7.4.150.0040.01417.40
7.4.140.0090.00917.86
7.4.130.0080.01116.73
7.4.120.0090.01016.51
7.4.110.0120.01216.66
7.4.100.0100.00716.70
7.4.90.0070.01116.73
7.4.80.0110.01119.39
7.4.70.0140.00616.61
7.4.60.0090.01216.64
7.4.50.0060.00316.66
7.4.40.0090.00622.77
7.4.30.0130.00316.57
7.4.10.0040.01514.91
7.4.00.0010.01415.05
7.3.330.0030.00313.50
7.3.320.0000.00713.34
7.3.310.0040.00416.41
7.3.300.0000.00716.36
7.3.290.0070.00716.49
7.3.280.0090.00716.47
7.3.270.0030.01417.40
7.3.260.0120.00616.52
7.3.250.0120.00716.61
7.3.240.0060.01016.46
7.3.230.0070.01016.49
7.3.210.0120.00816.69
7.3.200.0140.00419.39
7.3.190.0100.01316.75
7.3.180.0060.01616.55
7.3.170.0100.00716.46
7.3.160.0090.00916.66
7.3.130.0110.00714.89
7.3.120.0080.00814.93
7.3.110.0180.00014.69
7.3.100.0030.01214.82
7.3.90.0070.00714.82
7.3.80.0000.00914.98
7.3.70.0060.00314.69
7.3.60.0000.01215.04
7.3.50.0050.00514.61
7.3.40.0060.00914.93
7.3.30.0070.00714.67
7.3.20.0130.00316.77
7.3.10.0040.01116.63
7.3.00.0030.01016.40
7.2.330.0110.01017.00
7.2.320.0100.01317.04
7.2.310.0060.01316.91
7.2.300.0110.00616.78
7.2.290.0120.00917.05
7.2.260.0090.00914.98
7.2.250.0000.01515.43
7.2.240.0060.01215.16
7.2.230.0040.01115.01
7.2.220.0070.00715.54
7.2.210.0040.01115.48
7.2.200.0060.00615.11
7.2.190.0100.00315.24
7.2.180.0090.00615.11
7.2.170.0060.00915.16
7.2.160.0090.00615.08
7.2.150.0100.00317.10
7.2.140.0040.00717.15
7.2.130.0000.01016.99
7.2.120.0030.00716.78
7.2.110.0000.01117.11
7.2.100.0060.00616.65
7.2.90.0060.00617.06
7.2.80.0080.00616.81
7.2.70.0130.00317.04
7.2.60.0070.00917.07
7.2.50.0040.00816.74
7.2.40.0070.00717.02
7.2.30.0090.00917.14
7.2.20.0000.01616.95
7.2.10.0080.00417.21
7.2.00.0090.00318.20
7.1.330.0030.01415.79
7.1.320.0090.00015.62
7.1.310.0040.00715.81
7.1.300.0000.01215.93
7.1.290.0100.00315.55
7.1.280.0040.00815.48
7.1.270.0030.00615.68
7.1.260.0100.00715.88
7.1.250.0070.00315.63
7.1.240.0070.00715.89
7.1.230.0060.00315.95
7.1.220.0060.00815.88
7.1.210.0140.00715.52
7.1.200.0080.00915.84
7.1.190.0000.01515.77
7.1.180.0030.00915.94
7.1.170.0000.01016.00
7.1.160.0040.00815.97
7.1.150.0100.00315.62
7.1.140.0090.00015.80
7.1.130.0100.00015.58
7.1.120.0030.01015.63
7.1.110.0030.00615.64
7.1.100.0050.01017.01
7.1.90.0080.00415.96
7.1.80.0000.01115.79
7.1.70.0060.01116.39
7.1.60.0100.00617.82
7.1.50.0100.00816.28
7.1.40.0040.01515.51
7.1.30.0040.01215.86
7.1.20.0000.01315.48
7.1.10.0030.00615.57
7.1.00.0060.04119.08
7.0.330.0000.01315.32
7.0.320.0090.00315.30
7.0.310.0030.00615.29
7.0.300.0000.01115.38
7.0.290.0070.00715.56
7.0.280.0030.00915.32
7.0.270.0000.01315.21
7.0.260.0040.01115.56
7.0.250.0030.00715.41
7.0.240.0070.00315.36
7.0.230.0030.01015.57
7.0.220.0030.00915.51
7.0.210.0170.00015.15
7.0.200.0070.00415.91
7.0.190.0000.01215.37
7.0.180.0050.00515.39
7.0.170.0080.00615.55
7.0.160.0040.00815.47
7.0.150.0030.00715.30
7.0.140.0030.04118.71
7.0.130.0080.00415.36
7.0.120.0000.01515.49
7.0.110.0070.00715.36
7.0.100.0080.02517.57
7.0.90.0100.04317.74
7.0.80.0080.04717.74
7.0.70.0060.04117.77
7.0.60.0050.04517.73
7.0.50.0270.04317.96
7.0.40.0050.04916.79
7.0.30.0070.03816.76
7.0.20.0140.04316.79
7.0.10.0100.04116.66
7.0.00.0070.03216.85
5.6.400.0090.00314.63
5.6.390.0030.01314.71
5.6.380.0040.01814.46
5.6.370.0070.01014.71
5.6.360.0100.00714.50
5.6.350.0040.00714.56
5.6.340.0100.00014.22
5.6.330.0000.01414.57
5.6.320.0050.00514.65
5.6.310.0100.00714.06
5.6.300.0080.00414.45
5.6.290.0030.01014.46
5.6.280.0100.03717.79
5.6.270.0110.00714.45
5.6.260.0000.00914.50
5.6.250.0050.03817.63
5.6.240.0050.04617.72
5.6.230.0110.04217.64
5.6.220.0100.03417.72
5.6.210.0090.04117.59
5.6.200.0110.03617.85
5.6.190.0100.03517.59
5.6.180.0040.03617.65
5.6.170.0070.04317.76
5.6.160.0130.03417.89
5.6.150.0070.04117.82
5.6.140.0080.04518.08
5.6.130.0100.03517.70
5.6.120.0090.03617.65
5.6.110.0130.03817.92
5.6.100.0050.03817.78
5.6.90.0030.04517.76
5.6.80.0060.04517.34
5.6.70.0120.03217.38
5.6.60.0050.04417.45
5.6.50.0090.04017.26
5.6.40.0090.04317.41
5.6.30.0050.04117.41
5.6.20.0070.04217.57
5.6.10.0110.03817.41
5.6.00.0090.04017.44
5.5.380.0090.04017.45
5.5.370.0070.04217.60
5.5.360.0120.02317.41
5.5.350.0050.04517.47
5.5.340.0050.04317.71
5.5.330.0030.02617.69
5.5.320.0050.04817.60
5.5.310.0030.05017.50
5.5.300.0070.04217.57
5.5.290.0100.04217.61
5.5.280.0080.04417.73
5.5.270.0020.03317.66
5.5.260.0080.04617.64
5.5.250.0050.04517.53
5.5.240.0040.04417.46
5.5.230.0020.05117.35
5.5.220.0030.04217.25
5.5.210.0110.03517.16
5.5.200.0030.04617.47
5.5.190.0100.03817.40
5.5.180.0040.04717.34
5.5.170.0070.00714.23
5.5.160.0080.04317.37
5.5.150.0080.02717.39
5.5.140.0110.03417.27
5.5.130.0070.04117.22
5.5.120.0030.04717.20
5.5.110.0080.03817.47
5.5.100.0050.03517.32
5.5.90.0120.03717.16
5.5.80.0030.04717.11
5.5.70.0070.04217.17
5.5.60.0030.04517.21
5.5.50.0070.04317.16
5.5.40.0070.04517.28
5.5.30.0100.03817.18
5.5.20.0050.03917.15
5.5.10.0080.03517.34
5.5.00.0080.04017.36
5.4.450.0000.04715.39
5.4.440.0040.02915.29
5.4.430.0050.03915.13
5.4.420.0060.03615.30
5.4.410.0070.04215.26
5.4.400.0020.04714.98
5.4.390.0100.03715.07
5.4.380.0090.03514.93
5.4.370.0030.04314.90
5.4.360.0020.04715.12
5.4.350.0030.04315.12
5.4.340.0000.05015.15
5.4.330.0070.00411.01
5.4.320.0100.02914.98
5.4.310.0060.03615.17
5.4.300.0020.04315.08
5.4.290.0000.04215.08
5.4.280.0050.03814.86
5.4.270.0020.04014.95
5.4.260.0020.04615.13
5.4.250.0100.03715.08
5.4.240.0050.03915.07
5.4.230.0120.03515.19
5.4.220.0050.04115.02
5.4.210.0050.04315.06
5.4.200.0090.04015.09
5.4.190.0030.04314.94
5.4.180.0060.04014.94
5.4.170.0060.03815.17
5.4.160.0080.03714.79
5.4.150.0030.03514.93
5.4.140.0060.03813.67
5.4.130.0080.03713.82
5.4.120.0040.03213.76
5.4.110.0090.03713.75
5.4.100.0070.03213.51
5.4.90.0080.03813.70
5.4.80.0070.03713.73
5.4.70.0080.03813.67
5.4.60.0050.02613.72
5.4.50.0070.03713.81
5.4.40.0050.02613.63
5.4.30.0070.02213.79
5.4.20.0110.03013.75
5.4.10.0050.04013.71
5.4.00.0060.03613.32
5.3.290.0030.02912.64
5.3.280.0050.03512.69
5.3.270.0020.03812.63
5.3.260.0050.04212.72
5.3.250.0060.03912.74
5.3.240.0120.03512.72
5.3.230.0070.03512.67
5.3.220.0030.04112.66
5.3.210.0080.03812.52
5.3.200.0020.02812.65
5.3.190.0080.03712.67
5.3.180.0010.04312.70
5.3.170.0070.03512.63
5.3.160.0060.03612.78
5.3.150.0100.03712.60
5.3.140.0050.03812.60
5.3.130.0070.04212.51
5.3.120.0100.03512.71
5.3.110.0050.03812.63
5.3.100.0050.04112.39
5.3.90.0040.04212.40
5.3.80.0050.02612.25
5.3.70.0060.03512.34
5.3.60.0040.04012.44
5.3.50.0080.03812.30
5.3.40.0100.03312.11
5.3.30.0050.03812.33
5.3.20.0070.03212.14
5.3.10.0070.03211.96
5.3.00.0080.03512.09

preferences:
50.39 ms | 401 KiB | 5 Q