3v4l.org

run code in 300+ PHP versions simultaneously
<?php class QR { const METHOD = "aes-256-ctr"; /** * * Encrypts (without authenticating) * * @param string $input - json encoded array * @param string $key - encryption key (raw binary expected) * @param boolean $encode - set to TRUE to return base64-encoded * @return string (raw binary) */ public static function encrypt($input, $key, $encode = false) { $nonceSize = openssl_cipher_iv_length(self::METHOD); $nonce = openssl_random_pseudo_bytes($nonceSize); $ciphertext = openssl_encrypt( $input, self::METHOD, $key, OPENSSL_RAW_DATA, $nonce ); //Pack the IV and ciphertext together - concatenate return ($encode ? base64_encode($nonce.$ciphertext) : $nonce.$ciphertext); } /** * * Decrypts (but does not verify) * * @param string $input - ciphertext message * @param string $key - encryption key * @param boolean $encoded - are we expecting an encoded string? * @return string */ public static function decrypt($input, $key, $encoded = false) { if($encoded){ $input = base64_decode($message, true); if($input===false){ throw new Exception("Encryption failure"); } } $nonceSize = openssl_cipher_iv_length(self::METHOD); $nonce = mb_substr($input, 0, $nonceSize, "8bit"); $ciphertext = mb_substr($input, $nonceSize, null, "8bit"); $plaintext = openssl_decrypt( $ciphertext, self::METHOD, $key, OPENSSL_RAW_DATA, $nonce ); return $plaintext; } } class QRCrypt extends QR { const HASH_ALGO = "sha256"; /** * Encrypts then MACs an input * * @param string $input - plaintext input * @param string $key - encryption key (raw binary expected) * @param boolean $encode - set to TRUE to return a base64-encoded string * @return string (raw binary) */ public static function encrypt($input, $key, $encode = false) { list($encKey, $authKey) = self::splitKeys($key); //Pass to QR::encrypt $ciphertext = parent::encrypt($input, $encKey); //Calculate a MAC of hte IV and ciphertext $mac = hash_hmac(self::HASH_ALGO, $ciphertext, $authKey, true); return ($encode ? base64_encode($mac.$ciphertext) : $mac.$ciphertext); } /** * Decrypts an input (after verifying integrity) * * @param string $input - ciphertext input * @param string $key - encryption key (raw binary expected) * @param boolean $encoded - are we expecting an encoded string? * @return string (raw binary) */ public static function decrypt($input, $key, $encoded = false) { list($encKey, $authKey) = self::splitKeys($key); if($encoded){ $input = base64_decode($input, true); if($input===false){ throw new Exception("Encryption failure"); } } //Hash size in case HASH_ALGO is changed $hs = mb_strlen(hash(self::HASH_ALGO, "", true), "8bit"); $mac = mb_substr($message, 0, $hs, "8bit"); $ciphertext = mb_substr($message, $hs, null, "8bit"); $calculated = hash_hmac( self::HASH_ALGO, $ciphertext, $authKey, true ); if(!self::hashEquals($mac, $calculated)){ throw new Exception("Encryption failure"); } //Pass to QR::decrypt $plaintext = parent::decrypt($ciphertext, $encKey); return $plaintext; } /** * Splits a key into two separate keys; one for encryption * and the other for authenticaiton * * @param string $masterKey (raw binary) * @return array (two raw binary strings) */ protected static function splitKeys($masterKey) { // You really want to implement HKDF here instead! return [ hash_hmac(self::HASH_ALGO, 'ENCRYPTION', $masterKey, true), hash_hmac(self::HASH_ALGO, 'AUTHENTICATION', $masterKey, true) ]; } /** * Compare two strings without leaking timing information * * @param string $a * @param string $b * @ref https://paragonie.com/b/WS1DLx6BnpsdaVQW * @return boolean */ protected static function hashEquals($a, $b) { if (function_exists('hash_equals')) { return hash_equals($a, $b); } $nonce = openssl_random_pseudo_bytes(32); return hash_hmac(self::HASH_ALGO, $a, $nonce) === hash_hmac(self::HASH_ALGO, $b, $nonce); } } /** * QR Code encryption/decryption * */ //Set key here $key = '5B40ACCA3F81EFCFEA49139E7D7B6944ED716B76726F88DE2ECFAD30457ADD01'; //Set directory of qr.classes.php here with trailing slash $class = "./"; //Set input here $input = '{"id":2259,"name":"Darryl Rose"}'; //Are we encrypting or decrypting? (Set to "decrypt" for decryption) $decrypt = "encrypt"; /********************************************************************************/ $key = hex2bin($key); $input = trim(htmlspecialchars_decode($input)); $decrypt = $decrypt=="decrypt" ? true : false; exit(($decrypt ? QRCrypt::decrypt($input,$key,true) : QRCrypt::encrypt($input,$key,true)));
Output for 7.2.29 - 7.2.33, 7.3.16 - 7.3.33, 7.4.3 - 7.4.33, 8.0.0 - 8.0.30, 8.1.0 - 8.1.27, 8.2.0 - 8.2.17, 8.3.0 - 8.3.4
Fatal error: Uncaught Error: Call to undefined function openssl_cipher_iv_length() in /in/3VLT0:19 Stack trace: #0 /in/3VLT0(86): QR::encrypt('{"id":2259,"nam...', 'I\x89\x03\xDE\xA3\xDD\xBCGsrs\x02\xE5\x8C\x10...') #1 /in/3VLT0(191): QRCrypt::encrypt('{"id":2259,"nam...', '[@\xAC\xCA?\x81\xEF\xCF\xEAI\x13\x9E}{i...', true) #2 {main} thrown in /in/3VLT0 on line 19
Process exited with code 255.
Output for 7.1.7
XhO/BTWKOB17BBILxeOAhuK4tCYoeIuMFIZ2zrTO3oM6aQaApAEdOS6FL1r4X6SwhsyGVM9+HwDEnbiLJYPcsM5xeEfoNsHfIJOgMekRhdo=
Output for 7.1.6
WorNzXDKNY+cfq/b8/1rDPXRP0cVn2pak9affxw0ESqGvMVbhXvR5LOSXt7AYeQZ0ccKQ/EsyN116OBY/HCTayfHezaG+hvgwu78HZt+tGs=
Output for 7.1.5
F3zth/gXCtUcwqTFCSbXKgOkdT1ag8MnSRP64fLFoDQ/fdLqFxEntr6EkBkM8Fr7rd90dBntoZmfWyFzH1/X1MqukNVUom1t8ejZiccV9v4=
Output for 7.1.0
SE4TJ4/4mB1BYTz9XwSNIrInxskonZhAop6Wz71vbLrOoQoGPmnbS+EjvoUR9C6nE0Ms7JhTnrAzj6ta+E7awTZKqvJXKAHC1uMBbdJ978Y=
Output for 7.0.20
RkQqPaaN8EviP3SS2knGdi4N6YSfbzAvxSSvpXjgMfSYPm5BUj6A4IpNCKFTXS1+Ut11EGGdB2ZWdw8rik47t3VaiJMvvAKBRA0FFkB9fLU=
Output for 7.0.6
d0YYFRdT0CS7LODwrTOu4gWF9ARo/KBg5K03Edp34mZxVgTbW/hT60lZfDgjoiM1rPgnntbiqIWCInyOpfAUdRtPhzUAFbLEBtS7it6eQyc=
Output for 7.0.5
XPsWViNPStNmwmZncbPVLvFFWYtFFlGwVbBP4xAKrJIPvCHH9LGGVrN655QVIQDegv0+ZjAnmsKktuzYM7+VXy7S8iKG5CtB6NMmustFUD8=
Output for 7.0.4
E2dKOJsQ6J+hoeDXwJRBDOZ0r9jhE1vC4yKikuAvJ1hpUjlyHyQumPVZ6k0sM1BiKjxbUgB2MUZ3JLyO7yY+YXhaKMnXrVg9Dyb8iCW9vdI=
Output for 7.0.3
zzNPk7gZDAtm7AY/UNO9Rud3W5VclrNqJ3oxVPiJKflG3qgPF3s+Uh2H1mbn8mnkXvzmRIDehYcf9vAVGWPkOPOpbogWOzqdASyfrZdiEVw=
Output for 7.0.2
rZcjo5w7BJmrTyj5FZxn8LzX153LhwH9tqeY62CXwLd2fgageFAzP1/BLAoCg/VfyB1cLLsPUfTKsCvmgXZBT7bDE+4nTMpWw1iYabHlYm8=
Output for 7.0.1
KRX7zRmDNEsvkTe3VmGCTU29gyJwEcXhwUFaUEvwD2SYPTYKlIM2/Uqh0O90X6zqzxY2bRxnf5FBzDhNrjihdC1AjmhFjRDjwosY43V9Gmc=
Output for 7.0.0
XeHUlCGK8yVEIjciMUCGetFd8CNNVN8fUUS8QEGPDMOBEktnXACwWAohNkN5o1xL2pUXRBEiVKjUzSc/BJN6lmwg3U4tvg6dmuWBwQk6C1E=
Output for 5.6.28
nlqWH2IayWZ3D1uOs6WqRGoKsTXfSbf120FhI7bA/5II5HGfjrdRG8/7rWuMGYGlxS8YMrjYkI6obVMqf+1Uvvp9AxQXFFHLg9wPMy3pII8=
Output for 5.6.21
J8b88svjZg36J2V1rganzhne0lHiW8A1Eg2HWMu411i03PjpmdAUkq18kHk4g29i2ytJNdl/BOwCt67zZlr2L2gFLFRpPt+A2j7/ZQkr6jI=
Output for 5.6.20
SMSTeiCD/ShO5jbyVVXOsf1/RO0fbuIHCq8gSpAy6wVWIJ6ojfuFslX2aWc+yTRp7oqXtS0vTxKU++xKnwJoR8dpnlyWc6vXSMqVmEKuOWw=
Output for 5.6.19
ttVqxH3y3hYBtoIvsh5+QUBnYTXQp2Rdwjtuk/QuxZadGURlh/mAtiHFbTsgMTXKRe+k8R2jCiGIPYXw1DM7uhkOHsUi/hs+/z3I92WqmWE=
Output for 5.6.18
WOnk+7ZNAZGaCA3vjbPGc0t7qQThmRzqYiP/QJWYVA6yxCLs7bb/RWHFSfjb8Hkkc51pDw7tH4yR/eJTJxs+jfMne7TGAjxtzQJl3zGo8Fs=
Output for 5.6.17
3rfOrD3mnQobsOzVKHG5uKDcOeO3j5lcKr6WDiOcevMKoVkyQUeBwgHc+9I6GyQnAKFKPA0WCcqKYfflAReywBSssVhGxGRldLMockuPhdQ=
Output for 5.6.16
u5sWcIZUIyYjR5brVZik44zyhx8nqbEYyjgHJmeblUZyvqafVTVAMaLK4Nv9Ya8RKlrWlVfa2lWzdYxgQN0fSV5mG6Ge1ymngoY44mI6ne8=
Output for 5.6.15
Lr/IFnsm1/thb7dx1WuBbUlFe4Z6nG+h4QWRnVZldgas+Wz0p/VdkxLLRlqAfY4+dZUQ+VHLAj660LzUixakRGpiuXIgytqLc3LFPRqmK6k=
Output for 5.6.14
ZOJmYIHory6IVbJYzHzSWPaMVwwFoStVM7TtigHsRxrrBql4D6pgjUrgK848ZVjHHPTwhBW9VIaIzZM/NQCnCNCbRvXvPRGibH7sW3N9rLI=
Output for 5.6.13
cQHpPL8+HyWsXpBowe4zO+rmZTo/RZAd1R0Bx93yprSQgibihMX1+5L9vJr+UrG7yf8MLC/7Jgbkit4zslMU5qgUrGLRdKGjh49j+vKaGtY=
Output for 5.6.12
gk77jIi5+oshqOIcHhgvxT/4CAgPKOjJpZ69QkplCRhrf99eTkC8TZd0KQ/rIJ8HYeVNlDIUnlHoJlXLc5mUXLKxTI4Txi5hfHbU0onp+ak=
Output for 5.6.11
lfI4MmwkLddgmVjrIhRq3NRn7ZlKXT+aDJL6Fh8tMtNQviwykiWGZfn3t16Cxk+qPYAnyclufg+r9i+rng/pEpUvLjrJ7venWmTQmSvRQtM=
Output for 5.6.10
67da21XYKFe9SfslOvs+YTR5X+2S0XbkLqA2MTNb143BbCFngCXFp/AFGU6mAH4po3tOxh7mzdNO9+9ll56wAYUonV0LaXZAV+R+4Alo37M=
Output for 5.6.9
YRLjhWbO+Lkt0pLOOp010r7yWrjevsN2vAPPsDWMDxx8U0XJ1pZ47j6lwMAuUqTzQkRrMP34vxVAFQQvvqERwXTmU2TINAu1fXk+4c4T8VY=
Output for 5.6.8
Xbzjr8+SDRD2y/KrbuuG/zVr49KHYGZhf9/5a702cAE+biSIUUlXr5y2Zqt/LO9JL+6Ow3Y643dfDvvX4zXaFII0nMF/ey2rmsyCQ6mTjuk=
Output for 5.6.7
B3oKHRPhwERM4yEtdEUQiKIG4C2pwBUYy6uTzaUzVZJbawMevITZmULN4Xlq+j6sK58yKmUvmL4rqAMMdncPeaouFcmU/k/XWTWD+ojBLkg=
Output for 5.6.6
yZjzY9WZfg5V+xX51W/kJPeyh0wIBk6xxxJQWPyIw/LmqDt+XSevqJ/P1TWkz6fIgpugWGAOIWoJM/XLxN5nNP8tVQAXEjQdJuJKtcXNRko=
Output for 5.6.5
d8etyIBADbsWnlHW8iFMej9SmaBUjrWdCoEKXz3G2f2hQpt/e9/mr7VgUYUP2gNhjaOnYO09AGw9YI4/cmw3UFqvrLDMuLAROfTO8cVBzlU=
Output for 5.6.4
ED/BcLr9UHfmKJiR59BW6czGF3DEcG4u8TuAJFrNOW1H52P5YmbKDM2pJXyXZkYW2WnrhWGY2qElRHcDIWvM86lK9pq+BCrxi4RY7xZSA6E=
Output for 5.6.3
/RiB5rqYtIBS66ER8dSKhnSZaixFfUej1dVfm5RmtM1GqFjQY0iBitRcqyIulu1eLcjHWZR7OpgBOQD/mL38tSCQs4VjTg1vLLbEJybzN7Q=
Output for 5.6.2
8ZAobimnV7pEIpT98al5zA5aumTQNI2i67dfxzjzKhplgcMfrzd2AHceBUq1VSg0+z+l0mrnkEZfWhk1iMsiRYv6I55GFdrksWvllXZVYWY=
Output for 5.6.1
1k4m2cXzK7qzWZqy7eG9TzTOLkgPpMBDlcJ/w4Yn2gxFFZtDlCY/IsU//e73dzn2GOtPSrlDHv6kwXjlYw70pd3cBmFGmVg5mLEe8h0WQ0c=
Output for 5.6.0
F4eBtMk+n8RqlAX5HNYOCRV+ZHz3TGgKEg71y+iMIw4jO70WHzoY73ZyGq0npfRQPPOZIaXFbtcBvv7cCho+XhfG37DvxR26eITwYCTnS8g=
Output for 5.5.35
SFOu8RIbylzmoUkSIKKXKveNO1E8/sF3YMdhXA4a6JSsIV5PzyO50b9oN3AiMvJsWgg0gNVTmWFhDzMRVp72qxrHaw4m1RjPO1eTxopGeNU=
Output for 5.5.34
bJiclGHem5sjIVYlIrMmbYIqticcz/BbemlUgKdM+6p+Bz/FsK2o2I/K+mcCqKokFT7NI2Xs9VTEWVP87Snx17SPUbvgc5/Oi5j/vK2y0gI=
Output for 5.5.33
ieZL5LQ0Fagp9AJzaLQ2un60PwnZZOrW/IHQVrMyRMdI5Dzn2+AYqejRjDDYVXiPPEuh+mAVzbQXa5x5eP8v8tsASgzxPzYip0ygKRwKY9U=
Output for 5.5.32
dlEyHG/iLW2f3pCWkmkeqsRnOh7tgKfCbeDsD5WvLZbY/n6I5B0eARg54Y28zB/YNhuMQmDLGv25SS76vPOimOI6gDMkcAh9B5t/+AhhPGk=
Output for 5.5.31
SPX25+3gApjQgv9OaYViMLt7nwEuR1nkAxj879DLubVXr3hi0Y74204U2qAV53jN2mfWKWZBQ/9vceDAT7PkSY+PG2AGAC8SfLBun965/6E=
Output for 5.5.30
8WXvl1VF+xB6Mp8Pi/mN3Ux96u7x+sbbBeJ56o4KDqv7IRp966rg+c4Epz39jx8vw4IvH08APcqn5qtorvalMFED4el/bl9p5vhhpdE/5N8=
Output for 5.5.29
4IMZ+ERk9S/XK2PJmgkyB8ZibCGv3+rVlBC+USf6pf1S/FwnyxSl9w+WFJtWMoqHAKbQKiR0ZuAM0g2QuzGSyYzYhAWBfljbY1/w0xVtAxw=
Output for 5.5.28
ivHAv8D3IF592PNQTPDrIw4PkVer98UF0+RwfRLflKg9V58LTDcZlELObKMCbTI8UPjuiErdz7b4gIWalLNkEJLhq/AOJ/lRNuFa0ZPfkrU=
Output for 5.5.27
fgY03xovkWmToiaq9QCTG+zcDg3EUrfiEpPl5p0i87n632dVEpPs1blO8/d+/coClBotZ9T2F8hIIrvXRZMM8HYWLjlriMPPXXKgWGVcGRs=
Output for 5.5.26
kmrv+E9NxKCAht7XHvrNKktzsKL7XpOnWBq1oelG8KGhbDpzJPbqZy4KXJFWlXZQUjhQToswAkIZxAzZsfHdLjr7gd9AssvXRiqvUWyNjfI=
Output for 5.5.25
JgFcyOYslMWA/KG32XKSrXW5fBAzz1PWgd1oBbvT+fJGQdmyPx5PBOR1OFHJPoTx7MRccUM3Bmi/Om+bspJqjXasrnp1PcGPY8ucqKzl7Dg=
Output for 5.5.24
P+VQ8HRw5q6iF//YWYIa0aK2WzVst5O7TVoB8DP6DXxK1EoB46lns1pTL4OW0DvxZ/zFTBXuubgKzOs+skaM/V5533OkIYpP98XOKUjh+Kk=
Output for 5.5.23
awY1p5gSmIjxb8YH1uqdhBm+QDJmQAZ+S1vK0WJoEw8o3v9uYo0xaRBtT/c8680H15LPDh3ApRVJ41ZmKliRDI1OEhRAVbYkpkIttPONRzI=
Output for 5.5.22
Xnbz0JFQRPcZeuPEZdOlWiOQgscNcp16XX6GbyHOCDI3VqlzUGYP4aZVeOekCbXf4y/njttMhMYSCf5GDg60I2JnI6mIkChRg30hHHTQiF8=
Output for 5.5.21
HNlrBFB5cs+QGghbk8YZp0x1/itghUmiFXUDGCIjmVmIEYirBC2cC0EyNVwcKG1C1DDsE/88SXr4/GE4xFAo3w7Q/0peVBcS0qgDWvnhLWU=
Output for 5.5.20
CjuuT9MDEMaWmn/3Fo3xfYErUDBBv13vKkZn7An4xzn/j56p6sOmNbdILc/RW7YZk/RuDDrfIb50AfKva2Fj2CU0DDpLSScP2XMtckhpSRA=
Output for 5.5.19
h5qFGgsAZJFte1AVzUPOGKHbPiyO3Sb2qJ2dj7dj1a5P98z1CpmcDRr09NKy0eYam93Ook5CCv9MYrWZb3CexCFU3i79uvTrAeJwBEfL4Hg=
Output for 5.5.18
BIsmsNvCOjE2Kc35/0NVTPEe3hOzxlmabmvH4WI5Yok/iwco1dlvRvVAdVUgLUoydtKvDoK23flexABDPElzTnT4ga8FP4hLUQAwGXdgI7g=
Output for 5.5.16
1NrCZXI42NNQi3+d6maDF/x2+vVumgwkXL+kuLKcu3MFdAbM8nzHReU961+3mUnbC2vqeb8OgTahVY3Dl66qTvbOoZTUqH8ZmzRRLp3ael0=
Output for 5.5.15
09z0uUEZCAKKTuVCKx2N+F2aSablzVwITpjXCOdE3fbHXNdwr0HIfapwcZocgGx4zCw8oR79EShTA9hizWxLdLgZn1tFXF8XcKa9BeJvq0M=
Output for 5.5.14
SZiZNDinbiTEOa4DGAbhrpaMszRFX/Db7iqx8W5gASOGdeRjbGVpoWxQD7mS5GHgok01LRNQo7ZvLG3VxZ4zqdy/Be0QJgPccytRu/Z5iFg=
Output for 5.5.13
0SRVn5Wnl02twiEua8QZ5xccmJvE8d15MQ4t9bTtsbHbE2wJiSh47CCXOFaOFh05Vu606BDcpWhjwGSfTzh6V0fnYtz6Jvu7RB+cwZ04Mq0=
Output for 5.5.12
BYJK06BpFMFYj17sz9lhLKZ7IE1A68Pw1RTB7zaA5EbPTcRWztEWVJGM9ZdvXru4VJNlVVL79fohy6cqr1ZhNMmCbNa0hoLjKuExKj8xlI0=
Output for 5.5.11
yu9OPwsb4UO2OEE0x/kbq85h8GgBrCj+R3OIDBy0FvxXhotXPRmHa5FwGf+y5AUJQfAWK3ylwbxlbYzjmc6qDjQcphug9mvPILNmtrUkrjY=
Output for 5.5.10
8SzFoDbhRDvBOqGjj35bNQIT0kOKVkC2u1WMokhAbkpBFp4WPczMG1wb73tLPiJUfi/432us1e90kiS81yjfAw9TPGz1SlJhXTGEvExkO4g=
Output for 5.5.9
ubEwnUnohP+XkQQ94iPrIgz95YBZD4Bb52dP45+9Q63qZJ3otMUcCVFAF4QyHZ7pwAhAKagB2tRiA/H2z9rROFbdDjfqUhYLtkS/KLaeHp8=
Output for 5.5.8
GDY7GZeyPZ4skMkkb8re0bRDnSD0LoK6e5dV/8pUq+V2/R/VOIU0jeYx/NO6T+Qt+Fqu4N5OW+LUaRoTmaNozfMkCgDXsehZpOjisyq1M7A=
Output for 5.5.7
FI5teG4jfEqI1tHlKP3H+YBUC0VbEwrA6QECDA6fyXfcNRcNVtdpeRPcclxr33rQhpL78E3ZdkdxyW/XYwofSW9+3SDwho372A5nUH3PehQ=
Output for 5.5.6
Zq5eJOsIYQAMVuI7u/A8jXatqIX+B23B8DQzoOjRRwaejRobLUfse+rATi4d6Tnqi9D9MtZGDxUPPkz1nHPRlD72i5lKtf1Odxgk+Z/hIuA=
Output for 5.5.5
Lb7N2RYQlelKEKh9OLSkycqUoNgecokXKhFn9meFmwjzfGKTlPBu8xsDu2O0Q6m268uqhiIYULFaVCXFlglnChI0iL0mxIF6Hc/x0b6QDyM=
Output for 5.5.4
gFGWnRwtHQ2EWxNiy0cGCz1s3tWFOF6pyVEz7jKt6MPcF36IXoQfA37LvIiirUzKbgVwUcA8fJiG0cbg0vBtd/BuiXiflav95Fuprc1FYI8=
Output for 5.5.3
iGOMXKLFj8xc9IFJVrII3DET+8GLsMkUn54+OdP+kKgwlCBH6PkfcMAGWJu4hLzRvfGDFAE/KuMK0OwAAf9+iBUYMRnqQz4OZ4XrrO+ukMA=
Output for 5.5.2
QWpk5c9xXas1VLKZVYFwXOnvXpwqTG17toogWujglv78SbwL1UYj1RCM0sN0NDJ+2OyCYhLyb9CvybuNmvlb3JAXDo8GG5W7C91yqPPz6Sk=
Output for 5.5.1
9bjnuxi3X9Afm/77ZAPd2FsjkxJ4ODoxOu8LIubO2x6xDvXKQ5LzcWPHjua5/VAZsFsNJ6KXAophQkGI5idGk0DL/QxehuHqSALnkmY7eEU=
Output for 5.5.0
tDl5/9iJI9YADZbj+YJB/2pJJxHtNFFJn6t84Pxqea/C6qB4RNw7JErY5BZG86KSkBWwKeHF5SMIQ2uAbm386Tds+H5MVYFigD5bOzrEEzw=

preferences:
145.22 ms | 401 KiB | 205 Q